文章

Rust基础——结构体

结构体定义

struct是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合

使用struct关键字来定义一个结构体

1
2
3
4
5
struct User {
    username: String,
    email: String,
    active: bool
}

创建结构体的三种方式

  • 直接赋值初始化
  • 初始化简化语法
  • 结构体更新语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建结构体,在栈上分配内存
let user = User {
    username: String::from("username"),
    email: String::from("email"),
    active: true
};

// 使用字段初始化的简化语法
let username = String::from("username1");
let email = String::from("email");
let active = true;
let user1 = User { username, email, active};

// 结构体更新语法
let user2 = User {
    email: String::from("email"),  // 重新赋值字段
    ..user1  // 使用其他结构体的字段
},

注意,使用结构体更新语法时,等价于将其他结构体的字段赋值给新的结构体,赋值时会进行数据的移动和拷贝

例如以下代码,user1.username被移动到user2.usernameuser1.active被拷贝到user2.active,此时,user1失效

若在使用更新语法时,发生了所有权移动,则被用于更新的结构体在创建新的结构体后就不再有效,若没有发生所有权移动,则被用于更新的结构体依然有效

1
2
3
4
5
6
// 使用结构体更新语法等价于将其他结构体的字段赋值给新的结构体
let user2 = User {
    email: String::from("email"),
    username: user1.username,  // user1.username被移动到user2.username
    active: user1.active  // user1.active被拷贝到user2.active
};

元组结构体

在元组的基础上,可以创建特定元组类型的结构体,称为元组结构体

1
2
3
// 元组结构体即使元组内的类型相同,但依然是不同的类型,且与(i32, i32, i32)不兼容
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

元组结构体依然支持元组的解构和索引访问

1
2
3
4
let color = Color(0, 0, 0);
let red = color.0;  // 索引访问
// 解构赋值,注意(r, g, b)对应的类型是元组(_, _, _),不是Color(i32, i32, i32)
let Color(r, g, b) = color;

类单元结构体

类单元结构体就是没有任何字段的结构体,通常用于需要在某个类型上实现trait,但不需要在类型中存储数据

1
2
struct Unit
let unit = Unit;  // 创建类单元结构体

关联函数

rust可以在结构体中实现函数,函数在impl块中实现,与相应的结构体关联,称为关联函数

第一个参数为self参数的关联函数称为方法

1
2
3
4
5
6
7
8
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 { self.width * self.height }
}

方法参数中的&self表示关联结构体的不可变引用,是self: &Self的简写,其中

  • self是一个关键字,表示一个方法的接受者实例(receiver)
  • Self表示关联结构体的类型,可以用在参数类型和返回值类型上

对于selfSelf的用法,有以下三种情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
impl Rectangle {
    
    // 不使用引用,传入时会将关联结构体实例的所有权移动到方法内
    fn method1(self: Self) {
        // ...
    }
    
    // 使用不可变引用,可简写为&self
    fn method2(self: &Self) {
        // ....
    }
    
    // 使用可变引用,可简写为&mut self
    fn method3(self: &mut Self) {
        // ...
    }
}

不以self参数作为第一个参数的关联函数不作用在结构体的实例上,通常用作返回一个结构体实例的构造函数

1
2
3
4
5
impl Rectangle {
    fn square(size: u32) -> Self {
        Self { width: size, height: size }
    }
}
本文由作者按照 CC BY 4.0 进行授权