构造函数
只有一种方法可以创建用户定义类型的实例:命名它,并立即初始化其所有字段。
#![allow(unused)] fn main() { struct Foo { a: u8, b: u32, c: bool, } enum Bar { X(u32), Y(bool), } struct Unit; let foo = Foo { a: 0, b: 1, c: false }; let bar = Bar::X(0); let empty = Unit; }
就是这样。创建类型实例的任何其他方法都只是调用一个完全普通的函数,该函数执行一些操作并最终归结为“唯一真正的构造函数”。
与 C++ 不同,Rust 没有附带大量内置的构造函数类型。没有复制构造函数、默认构造函数、赋值构造函数、移动构造函数或任何其他构造函数。原因多种多样,但主要归结为 Rust 的“显式”哲学。
移动构造函数在 Rust 中毫无意义,因为我们不允许类型“关心”它们在内存中的位置。每种类型都必须准备好被盲目地内存复制到内存中的其他位置。这意味着纯粹的基于堆栈但仍然可移动的侵入式链表根本不会(安全地)发生在 Rust 中。
赋值构造函数和复制构造函数同样不存在,因为移动语义是 Rust 中唯一的语义。最多 x = y
只是将 y 的位移动到 x 变量中。Rust 确实提供了两种工具来提供 C++ 的面向复制的语义:Copy
和 Clone
。Clone 在道德上等同于复制构造函数,但它永远不会被隐式调用。您必须在要克隆的元素上显式调用 clone
。Copy 是 Clone 的一种特殊情况,其实现只是“复制位”。Copy 类型在移动时会被隐式克隆,但由于 Copy 的定义,这仅仅意味着不将旧副本视为未初始化的——一个空操作。
虽然 Rust 提供了一个 Default
trait 来指定在道德上等同于默认构造函数的内容,但很少使用此 trait。这是因为变量不会被隐式初始化。Default 基本上只对泛型编程有用。在具体上下文中,类型将为任何类型的“默认”构造函数提供静态 new
方法。这与其他语言中的 new
无关,也没有特殊含义。它只是一个命名约定。
TODO:谈谈“就地 new”?