Rust - Basic - 05 - Struct
Struct
Comprehension
基础语法
// 类型声明 struct User { active: bool, username: String, email: String, sign_in_count: u64, } // 实例化 let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, }; // 访问&修改 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"); // field init shorthand fn build_user(email: String, username: String) -> User { User { email, username, active: true, sign_in_count: 1, } } // struct update let user2 = User { email: String::from("another@example.com"), ..user1 } // 这里 user1 move 了,因为 user1.username (String 类型) 被 move 为 user2.username // 如果初始化 user2 的时候另外赋值 username,则 user1 不会被 moveMethod
struct impl 内的 function 称为 method 或者 associated function,method 与 field 可以同名
可同时存在多个 impl
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { // method self.width * self.height } fn width(&self) -> bool { // method 与 field 可以同名 self.width > 0 } fn square(size: u32) -> Rectangle { // 不带 &self 也可以 Rectangle { width: size, height: size, } } } // 可同时存在多个 impl impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } } fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!( "The area of the rectangle is {} square pixels.", rect1.area() ); if rect1.width() { println!("The rectangle has a nonzero width; it is {}", rect1.width); } }
Origin
…
Creating Instances From Other Instances With Struct Update Syntax
It’s often useful to create a new instance of a struct that uses most of an old instance’s values but changes some. You can do this using struct update syntax.
First, Listing 5-6 shows how we create a new User instance in user2 without the update syntax. We set a new value for email but otherwise use the same values from user1 that we created in Listing 5-2.
let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("another@example.com"),
sign_in_count: user1.sign_in_count,
};
Listing 5-6: Creating a new User instance using one of the values from user1
Using struct update syntax, we can achieve the same effect with less code, as shown in Listing 5-7. The syntax .. specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance.
let user2 = User {
email: String::from("another@example.com"),
..user1
};
Listing 5-7: Using struct update syntax to set a new email value for a User instance but use the rest of the values from user1
The code in Listing 5-7 also creates an instance in user2 that has a different value for email but has the same values for the username, active, and sign_in_count fields from user1. The ..user1 must come last to specify that any remaining fields should get their values from the corresponding fields in user1, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition.
Note that the struct update syntax is like assignment with = because it moves the data, just as we saw in the “Ways Variables and Data Interact: Move” section. In this example, we can no longer use user1 after creating user2 because the String in the username field of user1 was moved into user2. If we had given user2 new String values for both email and username, and thus only used the active and sign_in_count values from user1, then user1 would still be valid after creating user2. The types of active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the “Stack-Only Data: Copy” section would apply.