Rust 探索(七)—— 使用结构体来组织关联的数据
Rust 探索(七)—— 使用结构体来组织关联的数据
¶1. 定义并实例化结构体
Rust当中的结构体是一种自定义的数据类型,可以将多个值打包在一起,组成一个整体,听起来和面向对象编程语言当中类的概念似乎差不多
结构体的成员也是可以有不同的类型,并且其成员有对应的名称,相较于元组,它们更加灵活
使用struct
关键字可以定义结构体
1 | struct UserInfo { |
这就是一个UserInfo结构体,其中有4个字段,这些字段都是有对应名称的,有特定的含义,与平常所见的其他语言的类的定义十分相似
1 | let user = UserInfo { |
如果进行实例化,可以使用这样键值对的方式,user就是我们创建的新实例,给对应的字段赋了有意义的值
1 | print!("名称={}", user.username); |
通过.
可以根据字段名称访问实例中的字段
默认情况下,只能够访问实例的字段,而不能够进行修改,只有将实例声明为mut
可变类型,才可以对实例中的字段值进行修改
1 | let mut user = UserInfo { // 声明为可变 |
实例声明为mut
表明其中所有字段均可变,Rust不允许声明部分字段可变
¶2. 字段初始化简化
使用与字段名相同的变量进行初始化时,可以简化结构体的赋值写法
1 | let username = String::from("杰洛特"); |
当变量名称与结构体的字段名相同时,可以不用将键值分开书写,可以合并成一个,免去重复
¶3. 使用更新语法根据其他实例创建新实例
许多情况中,我们的新实例可能与原来已有的实例只是有细微的差别,重新新建一个从头开始初始化会比较啰嗦,此时就可以使用到Rust提供的更新语法
1 | let username = String::from("杰洛特"); |
使用..
表明剩下没有显式指明的内容均与给定的实例相同
¶4. 使用元组结构体
1 | struct Color(u8, u8, u8); |
元组结构体的形式类似于元组,其只需要在声明的时候指定类型就可以了
1 | let blue = Color(0, 0, 255); // 创建实例 |
直接对应赋值创建实例
访问其中的字段可以使用元组的索引方式
1 | println!("R={0}, G={1}, B={2}", blue.0, blue.1, blue.2); |
¶5. 空结构体
还有一种特殊的结构体,没有任何的字段,这种结构体被称为空结构体
1 | struct Thing; |
通常用来在这种类型上实现trait
,这与其他语言中的接口相似
¶6. 打印输出结构体
直接使用println!()
输出结构体代码无法通过编译
主要还是Rust没有为结构体提供默认的Display
实现,但是Rust也给出了解决方法,可以使用{:?}
或{:#?}
修改后又有新的问题
Debug
没有实现,但是同样给出了解决方法,我们再搭配上#[derive(Debug)]
试一下
1 | // 定义结构体的地方添加Debug标注 |
现在可以输出结构体的内容了,如果想要格式更好看些,可以替换{:#?}
¶7. 方法
如果把Rust的结构体看做是C++或是Java等语言的类,那么是不是还有成员方法的概念没有出现?其实Rust的结构体也是可以添加方法的
¶7.1. 定义方法
方法和函数相似但也有区别,主要就是方法是被定义在结构体、枚举类型或者trait对象内部的,类似于C++的成员函数,并且第一个参数永远是self
,指代调用该方法的结构体实例
1 |
|
¶7.2. 多个参数
直接在&self
后附加其他参数即可
1 | impl UserInfo { |
1 | user.earn(50.0); |
¶7.3. 关联函数
关联函数被称为函数而非方法,主要原因在于其不会作用于某个具体的实例,即没有&self
参数
关联函数一种常用的场景是通过一些参数、条件返回一个新的实例
1 | impl UserInfo { |
1 | let user = UserInfo::magicBuild(); |
使用结构体类型加上::
调用,这就类似于其他语言中的静态函数,与具体的实例无关,而只与类型相关
¶7.4. 多个impl
1 | impl UserInfo { |
一个结构体可以对应于多个impl
块,但通常没有特殊的必要还是推荐写在一起