Ber*_*rgi 11 struct encapsulation rust unit-type
我找到了四种不同的方法来创建struct没有数据:
struct A{} // empty struct / empty braced struct
Run Code Online (Sandbox Code Playgroud)struct B(); // empty tuple struct
Run Code Online (Sandbox Code Playgroud)struct C(()); // unit-valued tuple struct
Run Code Online (Sandbox Code Playgroud)struct D; // unit struct
Run Code Online (Sandbox Code Playgroud)(我将离开任意嵌套的元组,其中只包含()s和单变量enum声明,因为我理解为什么不应该使用这些元组).
这四个声明之间有什么区别?我会将它们用于特定目的,还是可以互换?
这本书和参考书令人惊讶地无益.我发现这个接受RFC(clarified_adt_kinds),其进入的差异位,即单元结构也声明了一个恒定值D和元组结构也声明构造函数B()和C(_: ()).但是,它没有提供关于使用哪个的设计指南.
我的猜测是,当我导出它们时pub,实际上可以在我的模块之外构造哪些类型存在差异,但我没有找到关于它的确凿文档.
struct D; // unit struct
Run Code Online (Sandbox Code Playgroud)
这是人们编写零大小struct.
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
Run Code Online (Sandbox Code Playgroud)
这些只是 basicstruct和 tuple 的特例,struct它们碰巧没有参数。RFC 1506解释了允许那些(他们不习惯)的理由:
允许具有 0 个字段的元组结构和元组变体。这个限制是人为的,可以轻松解除。处理元组结构/变体的宏编写者将很乐意摆脱这种特殊情况。
因此,它们很容易由宏生成,但人们很少会自己编写它们。
struct C(()); // unit-valued tuple struct
Run Code Online (Sandbox Code Playgroud)
这是 tuple 的另一个特例struct。在 Rust 中,()是一种与任何其他类型一样的类型,因此struct C(());与struct E(u32);. 虽然类型本身不是很有用,但禁止它会产生另一个需要在宏或泛型中处理的特殊情况(struct F<T>(T)当然可以实例化为F<()>)。
请注意,在 Rust 中有许多其他方法可以使用空类型。例如。可能有一个函数返回Result<(), !>来表明它不产生值,并且不会失败。虽然您可能认为()在这种情况下返回会更好,但如果您实现了一个要求您返回但让您选择和的特征,则您可能必须这样做。Result<T, E>T = ()E = !
这四个定义之间只有两个功能上的区别(稍后我将提到第五种可能性):
pub,其构造函数(也称为struct文字语法)是否可在其定义的模块之外使用。您的示例中唯一不能从当前模块外部直接构造的示例是C。如果尝试执行此操作,则会收到错误消息:
mod stuff {
pub struct C(());
}
let _c = stuff::C(()); // error[E0603]: tuple struct `C` is private
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为未标记该字段pub。如果声明C为pub struct C(pub ()),则错误消失。
您没有提到的另一种可能性是给出了更具描述性的错误消息:普通结构,其零pub成员数为零。
mod stuff {
pub struct E {
_dummy: (),
}
}
let _e = stuff::E { _dummy: () }; // error[E0451]: field `_dummy` of struct `main::stuff::E` is private
Run Code Online (Sandbox Code Playgroud)
(同样,您可以使用进行_dummy声明,从而使字段在模块外部可用pub。)
由于E的构造函数仅在stuff模块内部可用,stuff因此对何时以及如何E创建的值具有独占控制权。标准库中的许多结构都利用了这一点,例如Box(举一个明显的例子)。零大小类型的工作方式完全相同;实际上,从模块定义的外部,您唯一知道不透明类型为零大小的方法是调用mem::size_of。