5.1定义并实例化struct
什么是struct
- struct 结构体
- 自定义的数据类型
- 为相关联的值命名,打包=>有意义的组合
- 定义struct
- 使用struct关键字,并为整个struct命名
- 在花括号内,为所有字段(field)定义名称和类型
- 例如:
struct User { active: bool, username: String, email: String, sign_in_count: u64, } - 实例化struct
- 想要使用struct,需要创建struct的实例:
- 为每个字段指定具体值
- 无需按声明的顺序进行指定
struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn main() { let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; } - 想要使用struct,需要创建struct的实例:
- 如何进行访问
- 使用点标记法
- 一旦struct的实例是可变的,那么实例中所有的字段都是可变的
struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn main() { let mut user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; user1.email = String::from("anotheremail@example.com"); } - struct作为函数的返回值
- 函数的最后一个值作为返回值
struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn build_user(email: String, username: String) -> User { User { email: email, username: username, active: true, sign_in_count: 1, } } fn main() { let user1 = build_user( String::from("someone@example.com"), String::from("someusername123"), ); } - 字段初始化可简写
- 当字段名与字段值对应变量名相同时,就可以使用字段初始化简写的方式:
struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn build_user(email: String, username: String) -> User { User { email, username, active: true, sign_in_count: 1, } } fn main() { let user1 = build_user( String::from("someone@example.com"), String::from("someusername123"), ); } - struct 更新语法
- 当你想基于某个struct实例来创建一个新实例的时候,可以使用struct更新语法
struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn main() { // --snip-- let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; let user2 = User { email: String::from("another@example.com"), ..user1 }; } - tuple struct
- 可以定义类似tuple的struct,叫作tuple struct
- tuple struct 整体有个名,但里面的元素没有名
- 适用:想给整个tuple起名,并让它不同于其它的tuple,而且又不需要给每个元素起名
struct Color(i32, i32, i32); struct Point(i32, i32, i32); fn main() { let black = Color(0, 0, 0); let origin = Point(0, 0, 0); }
- 可以定义类似tuple的struct,叫作tuple struct
- unit-like struct(没有任何字段)
- 可以定义没有任何字段的struct, 叫做unit-like struct
- 适用于需要在某个类型上实现某个trait,但是里面又没有想要存储的数据
- struct 数据的所有权
+
struct User { active: bool, username: &str, email: &str, sign_in_count: u64, } fn main() { let user1 = User { email: "someone@example.com", username: "someusername123", active: true, sign_in_count: 1, }; }- 这里的字段使用了string 而不是 &str
- 该struct实例拥有其所有的数据
- 只要struct实例是有效的,那么里面的字段数据也是有效的
- struct里也可以存放引用,但这需要使用生命周期
- 生命周期保证只要struct实例是有效的, 那么里面的引用也是有效的
- 如果struct里面存储引用,而不使用生命周期,就会报错
- 这里的字段使用了string 而不是 &str
一个struct的例子
fn main() {
let rect1 = (30, 50);
println!(
"The area of the rectangle is {} square pixels.",
area(rect1)
);
}
fn area(dimensions: (u32, u32)) -> u32 {
dimensions.0 * dimensions.1
}
struct 方法
- 方法和函数类似:fn关键字、名称、参数、返回值
- 方法与函数不同之处:
- 方法是在struct的上下文中定义
- 第一个参数是self,表示方法被调用的struct实例
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!(
"The area of the rectangle is {} square pixels.",
rect1.area()
);
}
- 方法调用的运算符
- C/C++: object->something()和(*object).something()一样
- rust没有->运算符
- rust会自动引用或解引用
- 在调用方法时,Rust会根据情况自动添加 &、&mut或*,以便object可以匹配方法的签名。
- 方法参数
- 方法可以有多个参数
fn main() { let rect1 = Rectangle { width: 30, height: 50, }; let rect2 = Rectangle { width: 10, height: 40, }; let rect3 = Rectangle { width: 60, height: 45, }; println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); } - 创建一个关联函数
+
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle { width: size, height: size, } } } fn main() { let sq = Rectangle::square(3); } Rectangle::square(3);