创建零大小结构的多种方法之间有什么区别?

Ber*_*rgi 11 struct encapsulation rust unit-type

我找到了四种不同的方法来创建struct没有数据:

(我将离开任意嵌套的元组,其中只包含()s和单变量enum声明,因为我理解为什么不应该使用这些元组).

四个声明之间有什么区别?我会将它们用于特定目的,还是可以互换?

这本书和参考书令人惊讶地无益.我发现这个接受RFC(clarified_adt_kinds),其进入的差异位,即单元结构也声明了一个恒定值D和元组结构也声明构造函数B()C(_: ()).但是,它没有提供关于使用哪个的设计指南.

我的猜测是,当我导出它们时pub,实际上可以在我的模块之外构造哪些类型存在差异,但我没有找到关于它的确凿文档.

mca*_*ton 7

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 = !

  • 因此,其中大多数存在只是因为通用代码最终可以使用它们,而不是因为它们具有不同的功能?我想我很困惑,因为 [here](https://github.com/DoumanAsh/stm32l4x6_hal/blob/19f6233ef04e549825a3851e25e5829c253a5149/src/rcc/mod.rs#L65);直接使用了结构 C(())在其他地方](https://github.com/DoumanAsh/stm32l4x6_hal/blob/19f6233ef04e549825a3851e25e5829c253a5149/src/gpio/mod.rs#L17-L68)在相同的代码库中使用`struct A; (2认同)

tre*_*tcl 5

这四个定义之间只有两个功能上的区别(稍后我将提到第五种可能性):

  1. 语法(最明显)。麦卡顿的答案更加详细。
  2. 标记struct时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。如果声明Cpub 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