Rust学习记录--C5 Rust struct

C5 Rust struct

定义和实例化struct

定义struct

  • 使用struct关键字,并为它命名

  • 格式:

    • 在花括号内,为所有字段(field)定义名称和类型
  • 例子:

    rust 复制代码
    struct User{
    		// 先写名称:再写类型
        username:String,
        email:String,
        sign_in_count:u64,
        // 最后一个在现有的rust版本中好像不加,也可以了
        active:bool,
    }

实例化struct

  • 实例化struct(使用struct)

    • 为每个字段指定具体的值
    • 无需按照声明的顺序进行指定
  • 例子

    rust 复制代码
    fn main(){
        let user1 = User{
        			// 每个字段都要指定具体的值
            username: String::from("Xiaoming"),
        			// 顺序可以不一致
            active: true,
            email: String::from("xiaoming@163.com"),
            sign_in_count:12,
        };
    }
    
    struct User{
        username:String,
        email:String,
        sign_in_count:u64,
        active:bool,
    }

取得struct里面的某个值

  • 使用点标记法

    rust 复制代码
    user1.email

注意

  • 一旦struct的实例是可变的,那么实例中所有字段都是可变的

struct可以作为函数的返回值

  • 例子

    rust 复制代码
    fn build_user(email: String, username:String) ->User{
        return User{
            email:email,
            username:username,
            active:true,
            sign_in_count:01,
        };
    }

字段初始化简写

  • 当字段名与字段值对应变量名相同时,可以使用字段初始化简写

    rust 复制代码
    fn main(){
        let user2 = build_user(String::from("xiaohong@163.com"), String::from("xiaohong"));
        println!("email: {}, username: {}, active: {}, signInCount: {}", user2.email,user2.username, user2.active, user2.sign_in_count);
    }
    
    //函数传入参数名称和struct中定义的字段名称一样才可以简写
    fn build_user(email: String, username:String) ->User{
        return User{
            email,
            username,
            active:true,
            sign_in_count:01,
        };
    }
    
    struct User{
        email:String,
        username:String,
        sign_in_count:u64,
        active:bool,
    }

    错误示范:

struct更新语法

  • 基于已有的struct创建新的实例->使用struct更新语法

    rust 复制代码
    let user3 = User{
     username: String::from("Xiaoqiang"),
     email: String::from("Xiaoqiang@163.com"),
     sign_in_count: user1.sign_in_count,
     active: user1.active,
    };

    可以简写为

    rust 复制代码
    let user1 = User{
        username: String::from("Xiaoming"),
        active: true,
        email: String::from("xiaoming@163.com"),
        sign_in_count:12,
    };
    
    let user3 = User{
        username: String::from("Xiaoqiang"),
        email: String::from("Xiaoqiang@163.com"),
        // 表明剩下的两个字段直接使用user1的值
        ..user1
    };

Tuple struct

  • 定义类似tuple的struct,叫做tuple struct

    • tuple struct 整体有名字,但里面元素没有名字
    • 适用:相关整个tuple起名字,都是又不需要给各个元素起名字
  • 如何定义 tuple struct

    • struct tuple名称(元素类型, 元素类型, 元素类型);
    • 例子:
    rust 复制代码
    struct Color(i32,i32,i32);
    struct Point(i32,i32,i32);
    
    let black = Color(0,0,0);
    let origin_point = Point(0,0,0);
    • Color和Point都叫tuple struct,是不同的类型

Unit-Like Struct(没有任何字段)

  • 一个没有任何字段的struct
  • 适用于需要实现某个类型上的trait,但是里面没有想要存储的数据

struct数据的所有权

rust 复制代码
struct User{
    username:String,
    email:String,
    sign_in_count:u64,
    active:bool,
}
  • 字段使用了String而不是&str
    • 该struct拥有String字段的所有数据
    • 只有struct是有效的,里面的字段数据也是有效的
  • struct中可以存放引用,但是需要使用生命周期(以后会学)
    • 声明周期保证只有struct实例是有效的,里面的引用也是有效的
    • 如果struct直接存储引用,但是不用生命周期会报错

struct 例子

计算长方形面积的实现

  • 需求:计算长方形面积
  1. 初级:使用函数参数
rust 复制代码
fn main(){
    let w = 30;
    let l = 50;
    println!("Area: {}", area(w, l));
}

fn area(width:u32, length:u32)->u32
{
    return width*length;
}
复制代码
缺点:看起来w和l没有关联
  1. 使用tuple
rust 复制代码
fn main(){
    let w = 30;
    let l = 50;
    println!("Area: {}", area((w,l)));
}

// 使用tuple
fn area(dim:(u32,u32))->u32
{
    return dim.0*dim.1;
}
复制代码
缺点:长和宽虽然有关联了,但是没有名称了,可读性很差
  1. 使用struct + 函数实现
rust 复制代码
fn main(){
    let r1 = Rectangle{
        width:12,
        length:9,
    };
    let area = area(&r1);
    println!("Area: {}", area);
}
struct Rectangle{
    width:u32,
    length:u32,
}

fn area(rect: &Rectangle)->u32
{
    return rect.width*rect.length;
}
复制代码
优点: 长宽联系起来了且长宽有名字

输出一个struct

  • 想直接print r1这个struct

    • 结果会报错

    • 建议使用{:?} 或者 {:#?} ,但是加了之后还是会报错,报错是和debug有关

    • 添加#[derive(Debug)]{:?} 或者{:#?}

      • {:?}{:#?}的区别
        • {:?}是返回单行:
          Rectangle { width: 12, length: 9 }
        • {:#?}是返回有格式的,结构更清晰:
          Rectangle {
          width: 12,
          length: 9,
          }
  • 总结struct相关

    • std::fmt::Display
    • std::fmt::Debug
    • #[derive(Debug)]
    • {:?}
    • {:#?}

struct 方法

方法

  • 与函数的比较
    • 和函数类似:fn关键字/名称/参数/返回值
    • 和函数的不同点:
      • 方法是在struct(或者enum/trait对象)的上下文中定义
      • 方法的第一个参数是&self,表示方法被调用的struct实例
  • 上一个函数的缺点:单独的area函数很特殊,只适用于长方形,不适用于其他形状或者其他类型
    • ->将area函数和struct Rectangle关联到一起是最好的
    • 将原有的函数改成struct上定义的方法
  • 方法的定义和调用
    • 关键字impl
    • 方法的第一个参数是&self
    • 方法的调用:实例.函数名称() // 不需要显式的传入参数
    • 在调用方法时,rust根据情况自动添加&/&mut/*,以便于object可以匹配方法的签名
      • r1.area()(&r1).area() 等效
rust 复制代码
fn main(){
    let r1 = Rectangle{
        width:12,
        length:9,
    };
    // 方法的调用:实例.函数名称
    let area = r1.area();
    println!("Area: {}", area);
    println!("{:#?}", r1);
}

#[derive(Debug)]
struct Rectangle{
    width:u32,
    length:u32,
}

// struct的方法
impl Rectangle{
    fn area(&self)->u32
    {
        return self.width*self.length;
    }
}
复制代码
- 方法可以有多个参数,但是第一个必须是`&self`
rust 复制代码
impl Rectangle{
    fn area(&self)->u32
    {
        return self.width*self.length;
    }

	// 多个参数
    fn can_hold_another_rectangle(&self, other_rectangle: &Rectangle) -> bool
    {
        return self.width > other_rectangle.width && self.length > other_rectangle.length;
    }
}
复制代码
	![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7bba8c1e44054a368e5996249530d728.png)
- 上面这个叫关联函数,见下

关联函数

  • 关联函数:在impl块中定义不把self作为第一个参数的函数

    • (不是方法)
    • 不是在实例上调用的(我感觉像static)
    • 通常用于构造器->创建一个被关联类型的实例
    • 例子:String::from("xxx")
  • 关联函数的调用:类型名::函数名
    注意区别方法的调用和关联函数的调用的区别

    rust 复制代码
    #[derive(Debug)]
    struct Rectangle{
        width:u32,
        length:u32,
    }
    fn main(){
    	let r1 = Rectangle{
           width:12,
           length:9,
       };
       // 方法的调用:实例.函数名称
       let area = r1.area();
       println!("Area: {}", area);
       
    	//关联函数的调用
       let square = Rectangle::square(30);
    
       println!("{:#?}", square);
        
    }
    
    impl Rectangle{
    		// 方法
        fn area(&self)->u32
        {
            return self.width*self.length;
        }
        // 关联函数
        fn square(size: u32) -> Rectangle
        {
            return Rectangle { width: size, length: size };
        }
    }

多个impl块

  • 每个struct允许拥有多个impl块

2026/1/7

相关推荐
Fcy6481 分钟前
C++ 异常详解
开发语言·c++·异常
AI浩2 分钟前
约束模型下的目标检测置信学习
学习·目标检测·目标跟踪
机器视觉知识推荐、就业指导21 分钟前
Qt 和 C++,是不是应该叫 Q++ 了?
开发语言·c++·qt
m0_7482299939 分钟前
ThinkPHP快速入门:从零到实战
c语言·开发语言·数据库·学习
liu****39 分钟前
三.Qt图形界面开发完全指南:从入门到掌握常用控件
开发语言·c++·qt
風清掦44 分钟前
【江科大STM32学习笔记-04】0.96寸OLED显示屏
笔记·stm32·学习
胡西风_foxww1 小时前
ObsidianAI_学习一个陌生知识领域_建立学习路径和知识库框架_写一本书
人工智能·笔记·学习·知识库·obsidian·notebooklm·写一本书
Haooog1 小时前
AI应用代码生成平台
java·学习·大模型·langchain4j
非凡ghost1 小时前
ShareX(免费截图录屏软件)
windows·学习·软件需求
布茹 ei ai1 小时前
Python屏幕监视器 - 自动检测屏幕变化并点击
开发语言·python