在有类的编程语言中,组织数据的方式可以定义一个类,而在 Rust 中,组织数据的方式,使用 struct。struct 可以定义三种不同的类型,一种是带有字段名字的结构体,一种是没有字段名字的元组结构体,一种是没有任何字段的单元结构体。
定义 struct
带有字段名字的结构体
#[derive(Debug)]
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let user1 = User {
username: String::from("fred"),
email: String::from("fred@outlook.com"),
active: false,
};
println!("{:?}", user1);
}
注意上面的代码中
#[derive(Debug)]
,简单理解就是加上这个,可以给我们自定义的结构体添加上可打印的功能,后面就可以使用println!
来打印出结构体。
上面的代码中定义了一个 User 结构体,里面的每一个字段,前面是字段名,后面是字段的数据类型。在 main 函数中的代码,是创建一个 User 实例。
元组结构体
#[derive(Debug)]
struct Color(u8, u8, u8, u8);
fn main() {
let color = Color(255,255,255,255);
println!("{:?}", color);
}
上面的代码中,定义了一个元组结构体,用来存储颜色值。
单元结构体
#[derive(Debug)]
struct Unit;
fn main() {
let unit = Unit;
println!("{:?}", unit);
}
通过函数创建结构体
#[derive(Debug)]
struct User {
username: String,
email: String,
active: bool,
}
fn create_new_user(username: String, email: String) -> User {
User{
username,
email,
active: false,
}
}
fn main() {
let new_user = create_new_user(String::from("Jack"), String::from("jack@outlook.com"));
println!("{:?}", new_user);
}
上面的代码中,create_new_user 的形参名和结构体里字段名是一样的,所以可以直接简写,而不用写成 username: username
这样。
使用其他结构体数据填充新的结构体
#[derive(Debug)]
struct User {
username: String,
email: String,
active: bool,
}
fn main() {
let username = String::from("fred");
let email = String::from("fred@outlook.com");
let user1 = User { username, email, active: false };
println!("user1: {:?}", user1);
let username = String::from("jack");
let email = String::from("jack@outlook.com");
let user2 = User{username, ..user1};
println!("user2: {:?}", user2);
}
注意上面代码中,定义 user2 时,最后没有赋值 email 和 active 字段,而是使用了 ..user1 这样的代码,意思是说,除了手动赋值的字段,其他字段从 user1 中拷贝。
将 struct 作为函数参数
将结构体作为函数参数,通常传的是引用,否则结构体的所有权会被移动到函数里。
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let r1 = Rectangle { width: 10, height: 10 };
let area = get_area(&r1);
println!("area: {}", area);
}
fn get_area(r: &Rectangle) -> u32 {
r.width * r.height
}
为 struct 定义方法
在 Rust 中一切皆类型,可以为任何类型实现任何方法。相当于赋予一个东西,一种功能。
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn get_area(&self) -> u32 {
self.width * self.height
}
fn square(size: u32) -> Rectangle {
Rectangle {width: size, height: size }
}
}
fn main() {
let r1 = Rectangle { width: 10, height: 10 };
let area = r1.get_area();
println!("area: {}", area);
let square = Rectangle::square(20);
println!("square: {:?}", square);
}
为一个结构体实现的方法,需要放在 impl 结构体名 { }
内。方法形参中的 &self
是对当前实例的一个引用。而在 impl 块中,不以 self 做为参数的函数,称为关联函数,它们是与结构体相关联,而不是针对于某一个结构体实例,所以调用的时候,需要使用 结构体名::函数名
这样的形式来调用,就像 String::from("hello")
。
修改结构体的字段值
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn get_area(&self) -> u32 {
self.width * self.height
}
fn scale(&mut self, value: u32) {
self.width *= value;
self.height *= value;
}
fn square(size: u32) -> Rectangle {
Rectangle {width: size, height: size }
}
}
fn main() {
let mut r1 = Rectangle {width: 10, height: 10};
println!("r1: {:?}", r1);
r1.scale(2);
println!("r1: {:?}", r1);
}
要修改结构体,首先要定义成 mut 的,然后结构体的方法,也要是 &mut self
的。