# 结构体组织相关联的数据 [参考链接](https://kaisery.github.io/trpl-zh-cn/ch05-00-structs.html) ## 结构体的定义和实例化 定义结构体,需要使用 `struct` 关键字进行声明。 - 方式一 ```rust struct User { active: bool, username: String, email: String, sing_in_count: u64, } ``` 通过为每个字段指定具体值来创建这个结构体的 **实例**。创建一个实例需要以结构体的名字开头,接着在大括号中使用 `key: value` `键 - 值` 对的形式提供字段。其中 key 是字段的名字,value 是需要存储在字段中的数据值。 ```rust fn main() { let user1 = User { active: true, username: String::from("123"), email: String::from("1234@example.com"), sing_in_count: 1 }; // 若是需要可变 let mut user2 = User { active: true, username: String::from("123"), email: String::from("1234@example.com"), sing_in_count: 1 }; user2.active = true; user2.username = String::from("test"); } ``` > 整个实例都是可变的, Rust 并不允许只将某个字段标记为可变。 - 方式二 ```rust fn build_user(email: String, username: String) -> User { // 简化语法 User { active: true, username, email, sing_in_count: 1 } // User { // active: true, // username: username, // email: email, // sing_in_count: 1 // } } ``` #### 使用结构体更新语法从其他实例创建实例 ```rust fn main() { // -- snip -- // let user2 = User { // active: user1.active, // username: user1.username, // email: String::from("user2@example.com"), // sing_in_count: user1.sing_in_count, // }; // 简化写法 ..user1 必须放在最后 let user3 = User { email: String::from("another@example.com"), ..user1 }; } ``` #### 使用没有命名字段的元组结构体来创建不同的类型 ```rust struct Color(i32, i32, i32); struct Point(i32, i32, i32); fn main() { let black = Color(0,0,0); let origin = Point(0,0,0); } ``` #### 没有任何字段的类单元结构体 我们也可以定义一个没有任何字段的结构体!它们被称为 **类单元结构体**(_unit-like structs_)因为它们类似于 `()`,即“元组类型”一节中提到的 unit 类型。 ```rust struct AlwaysEqual; fn main() { let subject = AlwaysEqual; } ``` ## 结构体示例程序 [参考链接](https://kaisery.github.io/trpl-zh-cn/ch05-02-example-structs.html#%E7%BB%93%E6%9E%84%E4%BD%93%E7%A4%BA%E4%BE%8B%E7%A8%8B%E5%BA%8F) ## 方法语法 **方法**(method)与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。 ```rust #[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.height * self.width } // 可以选择将方法的名称与结构中的一个字段相同。 fn width(&self) -> bool { self.width > 0 } } fn main() { let rect1 = Rectangle { width: 100, height: 10, }; println!("The area of rectangle is {} square pixels.", rect1.area()); // The area of rectangle is 1000 square pixels. if rect1.width() { println!("The rectangle has a nonzero width; it is {}", rect1.width); // The rectangle has a nonzero width; it is 100 } } ``` #### 带有更多参数的方法 [参考链接](https://kaisery.github.io/trpl-zh-cn/ch05-03-method-syntax.html#%E5%B8%A6%E6%9C%89%E6%9B%B4%E5%A4%9A%E5%8F%82%E6%95%B0%E7%9A%84%E6%96%B9%E6%B3%95) ```rust #[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { // other 接收其它参数 fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } } 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)); // Can rect1 hold rect2? true println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // Can rect1 hold rect3? false } ``` #### 关联函数 所有在 impl 块中定义的函数被称为 **关联函数**(_associated functions_),因为它们与 impl 后面命名的类型相关。 > 注意用法:**[impl 后面命名的类型]::[关联函数]** ```rust #[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { // 正方形 fn square(size: u32) -> Self { Self { width: size, height: size, } } } fn main() { // 用法 let sq = Rectangle::square(3); println!("The value of sq is: {:?}", sq); // The value of sq is: Rectangle { width: 3, height: 3 } } ``` > 关键字 `Self` 在函数的返回类型中代指在 **impl 关键字后出现的类型**,在这里是 `Rectangle` #### 多个 impl 块 每个结构体都允许拥有多个 impl 块 ```rust impl Rectangle { // 正方形 fn square(size: u32) -> Self { Self { width: size, height: size, } } } impl Rectangle { // other 接收其它参数 fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } } ```