RUST 0x04 Struct
1 定义与实例化(Instantiating)Struct
Struct和tuple很像,因为它们都能存储不同的数据类型。但和tuple不同的是,恁需要命名每一个数据。这样做的好处是,struct比tuple更灵活——不需要依靠数据的顺序就能获取某一个特定的值。
例如:
struct User { // 以下的每一项叫做域(field) username: String, email: String, sign_in_count: u64, active: bool, }
注意中间用的是,
而不是;
。否则会抛出一个CE。最后一个,
可以不写。
为了使用我们创建的这个struct,我们需要为它创建一个实例,并以key: value
来赋值。我们不必按和上面相同的顺序来,如:
let user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, };
如果想从一个struct中得到某个特定的值,我们可以用.
。如果实例是可变的,那么我们还可用.
对某个特定的域赋值,如:
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");
值得注意的是,如果要这样做,那么整个实例必须是可变的,Rust不允许只有某几个域是可变的。
我们也可以手写一个初始化函数,如:
fn build_user(email: String, username: String) -> User { User { email: email, username: username, active: true, sign_in_count: 1, } }
运用简写域初始化(Field Init Shorthand)
为了方便,我们可以用field init shorthand来重写上面的函数:
fn build_user(email: String, username: String) -> User { User { email, username, active: true, sign_in_count: 1, } }
我们想使email: email,
,因为它们两者有着同样的名称,所以我们可以直接简写为email,
。
运用Struct Update Syntax从其他实例创建实例
如果要创建一个很多值都和一个旧的实例相同的实例,我们可以使用struct update syntax。
首先,是不用update syntax的方法:
let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), active: user1.active, sign_in_count: user1.sign_in_count, };
用update syntax..
,可以以更少的代码实现相同的效果:
let user2 = User { email: String::from("another@example.com"), username: String::from("anotherusername567"), ..user1 };
..
→ 剩下的其它域的值将会与给定的实例相同。
Using Tuple Structs without Named Fields to Create Different Types
我们也可以定义长得很像tuple的struct——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 Structs Without Any Fields
unit-like struct没有任何域,日后再说。
2 Method Syntax
Method和function很像:它们都是用fn
声明,且都能有参数和返回值。但是method是在struct(或enum等)里定义的,且第一个参数是self
。
定义Method
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() ); }
impl
→ implementationself
→ self (记得加&(虽然在这个程序里不加也可以)).
→ call Method Syntax
含更多参数的Method
impl Rectangle { fn area(&self) -> u32 { self.width * self.height } fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } }
Associated Functions
associated function就是写在impl
里却又不用self
做参数的函数。它们是函数,而不是method。比如String::from
。
associated function经常用来写构造函数,如:
impl Rectangle { fn square(size: u32) -> Rectangle { Rectangle { width: size, height: size } } }
要调用它,我们需要用::
,比如 let sq = Rectangle::square(3);
Mutiple impl
Blocks
每个struct都可以有多个impl
语句块,如:
impl Rectangle { fn area(&self) -> u32 { self.width * self.height } } impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } }
小结
struct可以用来创建传统类型,将相关的数据存在一起并命名。
method可以用来对struct的实例进行操作。
associated function可以用来创建namespace里的function。
参考
The Rust Programming Language by Steve Klabnik and Carol Nichols, with contributions from the Rust Community : https://doc.rust-lang.org/book/