结构体

1 定义

使用struct关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,称为字段(field)

例1.1:

struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}

创建一个实例需要以结构体的名字开头,接着在大括号中使用key: value 键-值对的形式提供字段,其中key是字段的名字,value是需要存储在字段中的数据值。实例中字段的顺序可以与声明不一致。

例1.2:

fn main() {
let user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("someone@example.com"),
sign_in_count: 1,
};
}

当参数名与字段名一致的时候,可以进行省略,称为字段初始化简写语法(field init shorthand)

例1.3:

fn build_user(email: String, username: String) -> User {
User {
active: true,
username, // username: username,
email, // email: email,
sign_in_count: 1,
}
}

对于可变性来说,结构体不允许单独的一个字段设置为可变。

使用结构体更新语法从其他实例创建实例

使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过结构体更新语法(struct update syntax)实现。

例1.4:

fn main() {
let mut user1 = User {
active: true,
username: String::from("someusername123"),
email: String::from("someone@example.com"),
sign_in_count: 1,
};

let user2 = User {
active: user1.active, // use user1
username: user1.username,
email: String::from("another@example.com"),
sign_in_count: user1.sign_in_count,
};
}

还可以进一步简写为以下形式:

例1.5:

fn main() {
// --snip--

let user2 = User {
email: String::from("another@example.com"),
..user1
};
}

2 元组结构体

当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。

元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。要定义元组结构体,以struct关键字和结构体名开头并后跟元组中的类型。

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}

3 *结构体Debug输出格式

例3.1:

#[derive(Debug)] // add
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

println!("rect1 is {:?}", rect1);
}

# output
rect1 is Rectangle { width: 30, height: 50 }

4 方法语句

使用impl块(impl 是 implementation 的缩写)引起一个结构体名称,块中的所有内容都将与结构体相关联。

例4.1:

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块中定义的函数被称为关联函数(associated functions),因为它们与impl后面命名的类型相关。我们可以定义不以self为第一参数的关联函数(因此不是方法),因为它们并不作用于一个结构体的实例。

例4.2:

impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}