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 不会被 move
Method
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.