结构体 struct
定义和实例化
#![allow(unused)] fn main() { struct User { active: bool, username: String, email: String, sign_in_count: u64, } }
上面定义了一个user结构体
fn main() { let mut user1 = User { active: true, username: String::from("someusername123"), email: String::from("someone@example.com"), sign_in_count: 1, }; user1.email = String::from("anotheremail@example.com"); }
上面创建了一个user的可变实例user1,注意整个实例都是可变的,rust不支持控制指定字段可变性
初始化时并不需要按照struct字段的顺序
创建实例时可省略字段名
#![allow(unused)] fn main() { fn build_user(email: String, username: String) -> User { User { active: true, username, email, sign_in_count: 1, } } }
使用更新语法 struct update syntax
fn main() { // --snip-- let user2 = User { active: user1.active, username: user1.username, email: String::from("another@example.com"), sign_in_count: user1.sign_in_count, }; //下面的struct update syntax比上面的简洁许多 let user2 = User { email: String::from("another@example.com"), ..user1 }; }
注意 stuct update syntax类似于使用 =赋值。上述的 user1的name所有权已经 moved到user2了。不能再次使用user1的name。但active和sign_in_count是实现copy存储在stack上的,所以可以再次使用。
元组结构体 Tuple Structs
struct Color(i32, i32, i32); struct Point(i32, i32, i32); fn main() { let black = Color(0, 0, 0); let origin = Point(0, 0, 0); }
注意 black和origin是不同类型,虽然他们的字段类型相同
元组结构体的字段没有名字,类似于元组可通过索引访问
类似于空元组()即unit的结构体
空结构体在你需要实现某些特性trait,但不想存储任何数据的时候很实用
struct AlwaysEqual; fn main() { let subject = AlwaysEqual; }
使用派生特性添加实用功能 Adding Useful Functionality with Derived Traits
struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!("rect1 is {}", rect1); }
使用println! 宏以{}打印结构体时,需要结构体实现Display trait
使用{:?}打印结构体时,需要结构体实现Debug trait
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!("rect1 is {rect1:?}"); }
以上将输出
rect1 is Rectangle { width: 30, height: 50 }
使用{:#?}将输出
#![allow(unused)] fn main() { rect1 is Rectangle { width: 30, height: 50, } }
另外一种方式是使用dbg!宏。dbg!宏将输出到stderr,而println!宏则输出到stdout。dbg!宏将会改变参数的所有权,println!宏是borowing参数的引用
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } fn main() { let scale = 2; let rect1 = Rectangle { width: dbg!(30 * scale), height: 50, }; dbg!(&rect1); }
输出
#![allow(unused)] fn main() { [src/main.rs:10:16] 30 * scale = 60 [src/main.rs:14:5] &rect1 = Rectangle { width: 60, height: 50, } }
方法 Method
方法method大体类似函数function,但method的第一个参数始终是self
定义方法
#[derive(Debug)] 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() ); }
其中&serf是self:&Self的语法糖,在impl块中Self就是这个块的类型别名。方法可以拿走所有权(使用self),也可以借用(&self)和可变借用(&mut self)
注意方法名可以和字段名相同
impl Rectangle { fn width(&self) -> bool { self.width > 0 } } fn main() { let rect1 = Rectangle { width: 30, height: 50, }; if rect1.width() { println!("The rectangle has a nonzero width; it is {}", rect1.width); } }
使用同名方法返回字段在其它语言叫getter
调用方法直接使用struct的实例即可,rust会自动处理和方法签名的Receiver匹配
方法可以有参数
#![allow(unused)] fn main() { 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 } } }
can_hold方法除了一个不可变借用的Receiver外还有一个同类型的不可变借用参数
相关函数 Associated Functions
所有定义在impl块中的函数都被称为associated functions
在某些不需要类型实例的清下可以定义第一个参数不是self的的函数(因为没有self,所以不是方法)
不是方法的associated function经常被用来作为返回该类型新实例的构造器;如常用的String::from就是String类型的构造器
#![allow(unused)] fn main() { impl Rectangle { fn square(size: u32) -> Self { Self { width: size, height: size, } } } }
如上面的square函数通过Self(该类型别名)方便的构造一个正方形Rectangle实例
调用associated function语法为Rectangle::square(3);
::语法同时用在associated function和modules创建的命名空间上
多个impl块
#![allow(unused)] fn main() { 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让你可以自定义类型用于存储多个相关联的数据- 在
impl可以定义和类型相关的函数(associated function),方法(method)也是一种让你可以指定struct实例行为的相关函数