Struct 创建零尺寸结构的多种方法之间有什么区别?

Struct 创建零尺寸结构的多种方法之间有什么区别?,struct,rust,encapsulation,unit-type,Struct,Rust,Encapsulation,Unit Type,我找到了四种不同的方法来创建一个没有数据的struct: (我不考虑只包含()s和单个变量enum声明的任意嵌套元组,因为我理解为什么不应该使用它们) 这四种声明之间有什么区别?我会将它们用于特定用途,还是可以互换 这本书和参考书出人意料地毫无用处。我确实发现了其中的差异,即单元结构也声明了一个常量值D,元组结构也声明了构造函数B()和C(:())。然而,它并没有提供一个关于为什么要使用它的设计指南 我的猜测是,当我使用pub导出它们时,在哪些类型的代码可以在我的模块之外构建方面存在

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

(我不考虑只包含
()
s和单个变量
enum
声明的任意嵌套元组,因为我理解为什么不应该使用它们)

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

这本书和参考书出人意料地毫无用处。我确实发现了其中的差异,即单元结构也声明了一个常量值
D
,元组结构也声明了构造函数
B()
C(:())
。然而,它并没有提供一个关于为什么要使用它的设计指南

我的猜测是,当我使用
pub
导出它们时,在哪些类型的代码可以在我的模块之外构建方面存在差异,但我没有找到关于这方面的结论性文档

struct D; // unit struct
这是人们编写零大小
struct
的常用方法

struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
这些只是basic
struct
和tuple
struct
的特例,它们碰巧没有参数。解释允许这些(他们不习惯)的理性:

允许具有0个字段的元组结构和元组变体。这种限制是人为的,可以轻易取消。处理元组结构/变体的宏编写者将很乐意摆脱这一特殊情况

因此,它们很容易由宏生成,但人们很少自己编写

struct C(()); // unit-valued tuple struct
这是tuple
struct
的另一个特例。在Rust中,
()
是一个与其他类型一样的类型,因此
结构C(())与结构E(u32)没有太大区别。虽然类型本身不是很有用,但禁止它会造成另一种需要在宏或泛型中处理的特殊情况(
struct F(t)
当然可以实例化为
F


请注意,还有许多其他方法可以在Rust中使用空类型。可以使用函数return
Result
来指示它不产生值,并且不能失败。虽然您可能认为在这种情况下返回
()
会更好,但如果您实现了一个特性,该特性指示您返回
结果,但允许您选择
T=()
E=

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

  • 语法(最明显)。更详细地说
  • 当结构被标记为
    pub
    时,它的(也称为)是否在其定义的模块之外可用
  • 您的示例中唯一一个不能从当前模块外部直接构造的是
    C
    。如果尝试执行此操作,将出现错误:

    mod stuff {
        pub struct C(());
    }
    let _c = stuff::C(());  // error[E0603]: tuple struct `C` is private
    
    发生这种情况是因为该字段未标记为
    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
    
    (同样,您可以通过使用
    pub
    声明
    \u dummy
    字段,使其在模块外部可用)

    由于
    E
    的构造函数只能在
    stuff
    模块中使用,
    stuff
    E
    的值的创建时间和方式具有独占控制权。标准库中的许多结构都利用了这一点,比如
    Box
    (举一个明显的例子)。零尺寸类型的工作方式完全相同;事实上,从定义不透明类型的模块外部,您知道不透明类型大小为零的唯一方法是调用

    另见

    中未提及装置类型首选项。恐怕没有客观的答案-(您可能希望将其发送到users.rust-lang.org或类似的网站。@E_net4您的意思是没有区别,这取决于偏好?(在这种情况下,具有专用语法的单元结构使得
    D
    成为最明显的选择)我的意思是,这主要取决于大小写。最明显的选择并不总是最好的选择。单位值的组合也会产生单位值。这还取决于公共API中是否允许从板条箱外部创建值。@E_net4如果其中一些允许从板条箱外部创建值,那么这听起来像是一个答案不要。这正是我想不出来的部分。你问两个问题:“有什么区别?”和“我什么时候使用它们?”其中一个是主题上的,另一个不是。如果你坚持主题上的一个,你可能会得到答案。因此,大多数这些存在只是因为泛型代码可能会与它们一起结束,而不是因为它们具有不同的功能?我想我之所以困惑是因为
    struct C(());
    直接使用,而在同一代码库中使用了结构A;
    。@trentcl在他的回答中提供了另一个很好的用例。谢谢,我想这就是我想要的。有什么方法可以使结构的构造函数公开吗?不应该手动构造
    框,因为它需要放置堆上的数据。但是使用私有构造函数的公共零大小结构的实际用例是什么?@kazemakase我知道有人会问,但我没有想到用例。这本书建议(尽管他们使用
    [u8;0]
    而不是
    ()
    ,原因不明)。我还可以想象,通过编译时和运行时的某种组合,使用这样的结构来控制对全局资源的访问
    struct A{} // empty struct / empty braced struct
    struct B(); // empty tuple struct
    
    struct C(()); // unit-valued tuple struct
    
    mod stuff {
        pub struct C(());
    }
    let _c = stuff::C(());  // error[E0603]: tuple struct `C` is private
    
    mod stuff {
        pub struct E {
            _dummy: (),
        }
    }
    let _e = stuff::E { _dummy: () };  // error[E0451]: field `_dummy` of struct `main::stuff::E` is private