struct
定义 struct
使用 struct 关键字,并为其命名。在花括号内,为所有字段(Field)定义名称和类型。
struct User{ username: String, email: String, sign_in_count: u64, active: bool, }
实例化 struct:
- 为每个字段指定具体值。
- 无需按照声明的顺序进行指定。
let user1 = User{ email: String::from("someone@example.com"), username: String:from("someusername123"), active: true, sign_in_count:1, }
访问 struct 里面的某个值:
- 使用点标记法。
- 一旦 struct 的实例是可变的,那么实例中的所有字段都是可变的。
let mut user2 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; user2.email = String::from("aaaa@example.com");
struct 作为函数的返回值。
let _user_info: User = test("aaa@ex.com".to_string(), "ccl".to_string()); fn test(email: String, username: String) -> User { User { username: username, email: email, sign_in_count: 1, active: true, } }
- 同名字段简写:
fn test(email: String, username: String) -> User { User { username, email, sign_in_count: 1, active: true, } }
struct 更新语法:
- 当想基于某个 struct 实例来创建一个新实例的时候,可以使用 struct 更新语法。
- 语法糖
..user_info
,将其余项赋值为user_info
的。
let _user_info2: User = User { email: String::from("another@example.com"), username: String::from("anotherusername"), active: user_info.active, sign_in_count: user_info.sign_in_count, }; let _user_info3: User = User { email: String::from("another@example.com"), username: String::from("anotherusername"), ..user_info };
Tuple struct
可以定义类似 tuple 的 struct,叫做 tuple struct。
- Tuple struct 整体有个名称,但里面的元素没有名称。
- 适用:想给整个 tuple 进行命名,并让它不同于其他 tuple,而且又不需要给每个元素起名。
定义 tuple struct:使用 struct 关键字,后边是名称以及里面的元素类型。
- 下例中的 black 与 origin 是不同类型是,属于不同 tuple struct 的实例。
struct Color(i32, i32, i32); struct Point(i32, i32, i32); let black = Color(0, 0, 0); let origin = Point(0, 0, 0);
Unit-Like Struct 没有任何字段
- 可以定义没有任何字段的 struct,叫做 Unit-Like struct。
- 适用于需要在某个类型上实现某个 trait, 但是在里面又没有想要存储的数据。
struct 数据的所有权
- 以前边的 User struct 为例,其中的字段使用 String 而不是 &str,则表示 User struct 拥有全部的字段所有权。
- 只要 struct 实例是有效的,那么里面的字段数据也是有效的。
- struct 里也可以存放引用,但这需要使用生命周期。
struct 方法
方法和函数类似:fn 关键字、名称、参数、返回值。
方法与函数不同:
- 方法是在 struct (或 enum、trait 对象)的上下文中定义。
- 第一个参数是 self,表示方法被调用的 struct 实例。
#[derive(Debug)] struct Rectangle { width: u32, length: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.length } } fn main() { let rect = Rectangle { width: 30, length: 50, }; println!("{}", rect.area()); println!("{:#?}", rect); }
在 impl 块里定义方法,方法的第一个参数可以是 &self,也可以获得其所有权或可变借用。和其他参数一样。同样可以获得更良好的代码组织。
方法参数,与普通函数类似任意携带:
impl Rectangle { fn area(&self) -> u32 { self.width * self.length } fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length } }
关联函数
可以在 impl 块里定义不把 self 作为第一个参数的函数名,它们叫关联函数(不是方法),例如
String::from()
。关联函数通常用于构造器。
impl Rectangle { fn area(&self) -> u32 { self.width * self.length } fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.length > other.length } fn square(size: u32) -> Rectangle { Rectangle { width: size, length: size, } } } let s = Rectangle::square(20); println!("{:#?}", s);
多个 impl 块
- 每个 struct 允许拥有多个 impl 块。
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.length
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.length > other.length
}
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
length: size,
}
}
}