结构体
在实例化一个结构体时将它整体标记为可变的,但是 Rust 不允许我们将结构体的某个字段专门指定为可变的。一旦实例可变,那么实例中的所有字段都将是可变的。
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
#![allow(unused)]
fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
}
当函数参数和结构体字段同名时,可以直接使用缩略的方式进行初始化,跟 TypeScript 中一模一样。
#![allow(unused)]
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};
..
语法表明凡是我们没有显示声明的字段,全部从 user1
中自动获取。需要注意的是 ..user1
必须在结构体的尾部使用。
值得注意的是:username
所有权被转移给了 user2
,导致了 user1
无法再被使用,但是并不代表 user1
内部的其它字段不能被继续使用。
#![allow(unused)]
fn main() {
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
#![allow(unused)]
fn main() {
struct AlwaysEqual;
let subject = AlwaysEqual;
// 我们不关心 AlwaysEqual 的字段数据,只关心它的行为,因此将它声明为单元结构体,然后再为它实现某个特征
impl SomeTrait for AlwaysEqual {
}
}
如果想在结构体中使用一个引用,就必须加上生命周期,否则就会报错。
{:?},{:#?}
dbg!宏:拿走表达式的所有权,打印出相应的文件名、行号等 debug 信息,最终还会把表达式值的所有权返回。
当解构一个变量时,可以同时使用 move
和引用模式绑定的方式。当这么做时,部分 move
就会发生:变量中一部分的所有权被转移给其它变量,而另一部分我们获取了它的引用。
在这种情况下,原变量将无法再被使用,但是它没有转移所有权的那一部分依然可以使用,也就是之前被引用的那部分。
枚举
任何类型的数据都可以放入枚举成员中: 例如字符串、数值、结构体甚至另一个枚举。
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let m1 = Message::Quit;
let m2 = Message::Move{x:1,y:1};
let m3 = Message::ChangeColor(255,255,0);
}
#![allow(unused)]
fn main() {
struct QuitMessage; // 单元结构体
struct MoveMessage {
x: i32,
y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
}
从代码规范角度来看,枚举的实现更简洁,代码内聚性更强,不像结构体的实现,分散在各个地方。
Rust 吸取了众多教训,决定抛弃 null
,而改为使用 Option
枚举变量来表述这种结果。
Option 枚举包含两个成员,一个成员表示含有值:Some(T), 另一个表示没有值:None
#![allow(unused)]
enum Option<T> {
Some(T),
None,
}
其中 T
是泛型参数,Some(T)
表示该枚举成员的数据类型是 T
,换句话说,Some
可以包含任何类型的数据。
只要一个值不是 Option<T>
类型,你就 可以 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。
#![allow(unused)]
fn main() {
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}
plus_one
通过 match
来处理不同 Option
的情况。