Rust中的结构体
因为学Rust的同学基本都是从C/C++过来的,所以对于Rust中的结构体就不用讲得太细了,因为基础内容都是差不多的,只是有一些地方会有小小的区别。
在前面数据类型的时候介绍过元组,在C++的泛型那块也有元组的出现,如果要追溯到C语言的层次的话,结构体才是复杂数据类型的鼻祖。在复杂数据类型这块,一切都是从C开始演化过来的,包括像C++的类,Java的类也是从C语言的结构体开始。到了Rust中,结构体的样子也是差不多的,语法上比较贴近C语言,因为它把成员函数(在Rust中称为关联函数或方法,这些叫法不重要,重要的是它所表达的意思)这些都通通放到impl中,从struct关键字开始看,有股浓浓的C语言的味道。
结构体的声明
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
对应C语言的风格
struct User {
bool active,
String username,
String email,
unsigned long sign_in_count
};
结构体的访问也是采用 ‘.’ 加成员的方式访问。
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let cukor = User {
active: true,
username: String::from("Cukor"),
email: String::from("123456@qq.com"),
sign_in_count: 886,
};
if cukor.active {
println!("{}上线了", cukor.username);
} else {
println!("{}不在线,请在{}留言", cukor.username, cukor.email);
}
}
当参数赋值给结构体成员同名时可以简写,例如:
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
也可以通过其他结构体对象初始化当前结构体对象。
fn main() {
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("another@example.com"),
sign_in_count: user1.sign_in_count,
};
}
Rust提供了..
语法,其作用是指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。
fn main() {
let user2 = User {
email: String::from("another@example.com"),
..user1
};
}
fn main() {
let user2 = User {
email: String::from("another@example.com"),
username: user1.username,
active: user1.active,
sign_in_count: user1.sign_in_count,
};
}
请注意,结构更新语法就像带有 =
的赋值,因为它移动了数据,就像我们在“变量与数据交互的方式(一):移动”部分讲到的一样。在这个例子中,我们在创建 user2
后不能再使用 user1
,因为 user1
的 username
字段中的 String
被移到 user2
中。如果我们给 user2
的 email
和 username
都赋予新的 String
值,从而只使用 user1
的 active
和 sign_in_count
值,那么 user1
在创建 user2
后仍然有效。active
和 sign_in_count
的类型是实现 Copy
trait 的类型,所以我们在“变量与数据交互的方式(二):克隆” 部分讨论的行为同样适用。
使用没有命名字段的元组结构体来创建不同的类型
这种结构体称之为:元组结构体。
元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。
当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
元组结构体就是可是省略成员名的结构体操作,像以上的Color,都知道它是由三种原基色构成(red, green, blue),使用元组结构体就可以减少red等这些的名字,因为我们早就已经习惯他们了。包括point也是,我们都知道是x,y,z轴。
没有任何字段的类单元结构体
我们也可以定义一个没有任何字段的结构体!它们被称为 类单元结构体(unit-like structs)因为它们类似于 ()
,即“元组类型”一节中提到的 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。
struct AlwaysEqual;
fn main() {
let subject = AlwaysEqual;
}
要定义 AlwaysEqual
,我们使用 struct
关键字,我们想要的名称,然后是一个分号。不需要花括号或圆括号!然后,我们可以以类似的方式在 subject
变量中获得 AlwaysEqual
的实例:使用我们定义的名称,不需要任何花括号或圆括号。想象一下,我们将实现这个类型的行为,即每个实例始终等于每一个其他类型的实例,也许是为了获得一个已知的结果以便进行测试。我们不需要任何数据来实现这种行为,你将在第十章中,看到如何定义特性并在任何类型上实现它们,包括类单元结构体。
官方文档:
结构体的定义和实例化 - Rust 程序设计语言 简体中文版 (kaisery.github.io).