Files
DefectingCat.github.io/content/posts/chapter-9-struct.mdx
2025-03-18 09:57:13 +08:00

138 lines
4.1 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 第 9 章 结构体
date: '2025-02-12'
tags: [Rust]
---
Rust 有 3 种结构体类型:具名字段型结构体、元组结构体和单元型结构体。
- 具名型结构体:为每个组件命名。
- 元组型结构体:按组件出现的顺序标识他们。
- 单元型结构体:没有组件。
## 具名结构体
```rust
struct GrayscaleMap {
pixels: Vec<u8>,
size: (usize, usize),
}
```
与其他所有语法项一样,结构体默认情况下是私有的,仅在声明它们的模块及其子模块种可见。可以通过在结构体的定义前加上 `pub` 来是结构体在其模块外部可见。结构体中的每个字段也是默认私有的。
```rust
pub struct GrayscaleMap {
pub pixels: Vec<u8>,
pub size: (usize, usize),
}
```
其他模块不能按名称访问私有字段或使用结构体表达式来创建新的 `GrayscaleMap` 值。
在结构体表达式中,如果具有名字的字段后面跟着 `.. EXPR`,则任何未提及的字段都会从 `EXPRE`(必须是相同结构体的另一个值)中获取它们的值。
```rust
struct Broom {
name: String,
height: u32,
health: u32,
position: (f32, f32, f32),
intent: BroomIntent,
}
#[derive(Copy, Clone)]
enum BroomIntent {
FetchWater,
DumpWater,
}
fn chop(b: Broom) -> (Broom, Broom) {
let mut broom1 = Broom {
height: b.height / 2,
..b
};
let mut broom2 = Broom {
name: broom1.name.clone(),
..broom1
};
broom1.name.push_str(" I");
broom2.name.push_str(" II");
(broom1, broom2)
}
```
## 元组型结构体
元组型结构体顾名思义类似于元组:
```rust
struct Bounds(usize, usize);
```
表达式 `Bounds(1024, 768)` 看起来像一个函数调用,实际上它确实是,级定义这种类型时也隐式定义了一个函数:
```rust
fn Bounds(elem0: usize, elem1: uszie) -> Bounds { ... }
```
元组型结构体适用于创造**新类型**newtype即建立一个只包含单组件的结构体以获得更严格的类型检查。
## 单元型结构体
单元型结构体声明了一个根本没有元素的结构体类型:
```rust
struct onesuch;
```
这种类型的值不占用内存,很像单元类型 `()`。Rust 既不会在内存中实际存储单元类型的值,也不会生成代码对它们进行操作,因为仅通过值的类型它就能知道关于值的所有信息
## 结构体布局
在内存中,具名字段结构体和元组型结构体是一样的:值的集合以特定的方式在内存中布局。
```rust
struct GrayscaleMap {
pixels: Vec<u8>,
size: (usize, usize),
}
```
与 C 和 C++ 不同Rust 没有具体承诺它将如何在内存中对结构体的字段或元素进行排序。然而Rust 确实承诺会将字段的值直接存储在结构体本身的内存块中。JavaScript、Python 和 Java 会将 `pixels` 值和 `size` 值分别放在它们自己的分配的堆上的块中,并让 `GrayscaleMap` 的字段指向它们,而 Rust 会将 `pixel` 值和 `size` 值直接嵌入在 `GrayscaleMap` 值中。只有由 `pixels` 向量拥有的在堆上分配的缓冲区才会留在它自己的块中。
可以使用 `#[repr(C)]` 属性要求 Rust 以兼容 C 和 C++ 的方式对结构体进行布局。
## 方法
在 `impl` 块中定义的函数被称为关联函数,因为它们是与特定类型相关联的。与关联函数相对应的是自由函数,它是未定义在 `impl` 块中的语法项。
`impl` 块知识定义 `fn` 的集合,每个定义都会成为块顶部命名的结构体类型上的一个方法。
当调用一个需要引用的方法时,我们不需要自己借用可变引用,常规的方法调用语法已经隐式的处理了这一点。
```rust
struct Queue<T> {
older: Vec<T>,
younger: Vec<T>,
}
impl<T> Queue<T> {
pub fn push(&mut self, item: T) {
self.younger.push(item);
}
}
let mut q = Queue {
older: vec![1],
younger: vec![],
};
q.push(2);
```
只需要编写 `q.push()` 就可以借入对 `q` 的可变引用,就好像写的是 `(&mut q).push()` 一样,因为这是 `push` 方法的 `self` 参数所要求的。