Rust 学习 06
archive time: 2022-05-14
终于开始讲 struct 了
Struct
struct
是自定义类型, 是积类型, 与之相对的是枚举 (enum), 和类型
简单理解, 积类型就是说要把所有字段一起出现才能示例化的类型, 而和类型就是字段里出现一个就行
struct User {
username: String,
email: String,
acount: u16,
active: bool,
}
// ...
let user = User { // 顺序可以不一样
// 但是每个字段都需要赋值
email: String::from("someone@example.com"),
username: String::from("someuser"),
active: true,
acount: 1,
}; // 注意分号
// 访问某个字段
println!("{}", user.email); // => someone@example.com
如果要对某个字段重新赋值或者修改值, 那么可以将实例声明为可变的
但是如果实例是可变的, 那么每个字段都将是可变的
// 现在实例是可变的
let mut user = User {
email: String::from("someone@example.com"),
username: String::from("someuser"),
active: true,
acount: 1,
};
// ...
user.username = String::from("kandscode");
println!("{}", user.username); // => kandscode
如果用于实例的变量和字段名相同, 可以简写
let email = String::from("someone@example.com");
let user = User {
email, // 简写
username: String::from("someuser"),
active: true,
acount: 1,
};
我们还可以从一个现有的结构体实例来创建一个新的实例
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someuser"),
active: true,
acount: 1,
};
let user2 = User {
acount: 1, // 除了 acount 不一样
..user1 // 其余和 user1 一样
};
但是要小心, 这样创建的实例之间是有关联的
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someuser"),
active: true,
acount: 1,
};
let mut user2 = User {
acount: 1,
..user1
};
// 不允许 因为 String 没有实现 Copy trait
// 所以这里是移动语义
user2.email = String::from("someone@another.com");
println!("{}", user1.email);
对应报错是
error[E0382]: borrow of moved value: `user1.email`
--> src\main.rs:20:20
|
14 | let mut user2 = User {
| _____________________-
15 | | acount: 1,
16 | | ..user1
17 | | };
| |_____- value moved here
...
20 | println!("{}", user1.email);
| ^^^^^^^^^^^ value borrowed here after move
|
= note: move occurs because `user1.email` has type `String`, which does not implement the `Copy` trait
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
所以要注意类型, 小心使用这个语法
但是这样是可以的
println!("{}", user1.active); // user1 还是可用
Tuple-Like Struct
tuple-like struct 整体有名字, 但是字段没有名称
struct Color(i8, i8, i8);
// ...
let black = Color(0, 0, 0);
println!("{}", black.0) // 访问第一个字段
Unit-Like Struct
就是没有字段的结构体
一般用于想在某个类型上实现某个 trait
但是又没有数据
struct AlwaysEqual;
let subject = AlwaysEqual;
// 我们不关心 AlwaysEqual 的字段数据, 只关心它的行为
// 因此将它声明为单元结构体, 然后再为它实现某个特征
impl SomeTrait for AlwaysEqual {
// ...
}
Example
一个计算矩形面积的例子
#[derive(Debug)] // 默认实现Debug
struct Rectangle {
width: u8,
length: u8,
}
fn area(rec: &Rectangle) -> u8 {
return rec.width * rec.length;
}
fn main() {
let rec = Rectangle {
length: 8,
width: 7,
};
println!("{}", area(&rec));
// {:#?} 要比 {:?} 要更加清晰
println!("{:#?}", rec); // 使用debug方式打印
}
// =>
/** output
56
Rectangle {
width: 7,
length: 8,
}
**/
好, 暂时就学到这里罢, 原神, 启动!