结构体
结构体允许我们命名多个相关的值并组合在一起。 结构与元组相似,不同的是结构体需要为每个数据赋予名字来表达它们的意义,结构体正是因为这些名字变得比元素要更加灵活。
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}创建实例之后,可以通过点号来访问结构体的特定字段。
let mut user1 = User {
username: String::from("someusername123"),
email: String::from("[email protected]"),
sign_in_count: 1,
active: true,
};
user1.email = String::from("[email protected]");一旦实例可变,那么实例中的所有字段都是可变的,不允许部分字段可变。
当变量名与字段名一致的时候,可以使用字段初始化简写:
fn build_user(username: String, email: String) -> User {
User {
username,
email,
active:true,
sign_in_count:1,
}
}还可以根据一个实例来创建一个新实例:
let user2 = User {
email: String::from("[email protected]"),
username: String::from("anotherusername"),
..user1 // 这里的双点号表示剩下还没有显式赋值的都与user1的值相同。
};元组结构体
使用一种类似于元组的方式定义结构体,这种结构体就叫做元组结构体。其实就是为元组取名,但是就算元组结构体定义一样,名字不同也是不同的类型。
定义的每一个结构体都拥有自己的类型,即便结构体中的字段拥有完全相同的类型.
例如:
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
// 这里black和origin是不同的类型
let black = Color(0,0,0);
let origin = Point(0,0,0);空结构体
没有任何字段的结构体,与空元组()十分相似,被称为空结构体。
结构体数据的所有权
上面的结构体示例中,使用自持有所有权的
String类型而不是&str,因为希望这个结构体具有自身全部数据的所有权,其实也可以在结构体中存储指向其它数据的引用,但是需要用Rust中独有的生命周期来解决这个问题I。
通过trait增加实用功能
先创建一个类型:
struct Rectangle {
width: u32,
height: u32,
}尝试打印Rectangle实例的信息,在println!宏中如果格式化动词为{},需要类型实现std::fmt::Display trait,如果格式化动词为{:?}或者{:#?},需要实现std::fmt::Debug trait。
通过添加#[derive(Debug)]来实现std::fmt::Debug trait
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}Rust提供了很多可以通过derive注解来派生trait。
方法
方法的概念与其它面向对象的语言中对象的方法一样。
方法总是定义在某个结构体中,第一个参数永远都是self。
可以为上面的Rectangle类型实例实现一个获取面积的area的方法:
impl Rectangle {
fn area(self) -> u32 {
self.width * self.height
}
}调用方法为:
rect.area()
// 实际上也是调用一个函数 area(rect)因为方法的第一个参数是self,会发生移动,所以如果希望调用完方法后仍然能够继续需要变量,方法的参数类型需要修改为&self,如果方法中还会修改实例的数据,那么类型为&mut self。
自动引用和解引用
在实例调用方法的时候,我们可以直接使用点来调用方法,而不需要在于方法的第一个参数是
self还是&self,&mut self。 Rust会自动为调用者添加&, &mut, *,让其符合方法的签名。
关联函数
关联函数是在impl块中定义的不需要接收self作为参数的函数,这类函数与结构体相关,称为关联函数。在面向对象的语言中相当于类的静态方法。
例如为一个类型定义一个New函数:
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle{width:size, height:size}
}
}多个impl块
每个结构体可以拥有多个impl块。 可以对方法进行分类,写在不同的impl中,便于理解。后面实现trait也经常需要多个impl块。