在有类的编程语言中,组织数据的方式可以定义一个类,而在 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 的。