Rust 有 3 种结构体类型:具名字段型结构体、元组结构体和单元型结构体。
- 具名型结构体:为每个组件命名。
- 元组型结构体:按组件出现的顺序标识他们。
- 单元型结构体:没有组件。
具名结构体
struct GrayscaleMap {
pixels: Vec<u8>,
size: (usize, usize),
}
与其他所有语法项一样,结构体默认情况下是私有的,仅在声明它们的模块及其子模块种可见。可以通过在结构体的定义前加上 pub
来是结构体在其模块外部可见。结构体中的每个字段也是默认私有的。
pub struct GrayscaleMap {
pub pixels: Vec<u8>,
pub size: (usize, usize),
}
其他模块不能按名称访问私有字段或使用结构体表达式来创建新的 GrayscaleMap
值。
在结构体表达式中,如果具有名字的字段后面跟着 .. EXPR
,则任何未提及的字段都会从 EXPRE
(必须是相同结构体的另一个值)中获取它们的值。
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)
}
元组型结构体
元组型结构体顾名思义类似于元组:
struct Bounds(usize, usize);
表达式 Bounds(1024, 768)
看起来像一个函数调用,实际上它确实是,级定义这种类型时也隐式定义了一个函数:
fn Bounds(elem0: usize, elem1: uszie) -> Bounds { ... }
元组型结构体适用于创造新类型(newtype),即建立一个只包含单组件的结构体,以获得更严格的类型检查。
单元型结构体
单元型结构体声明了一个根本没有元素的结构体类型:
struct onesuch;
这种类型的值不占用内存,很像单元类型 ()
。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
的集合,每个定义都会成为块顶部命名的结构体类型上的一个方法。
当调用一个需要引用的方法时,我们不需要自己借用可变引用,常规的方法调用语法已经隐式的处理了这一点。
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
参数所要求的。