struct - 如何为&Struct实现Default?

标签 struct rust lifetime

在阅读了很多使用rust 的书之后,我认为我已经开始了解生命周期的要点,但是对我来说,另一个问题是我们需要使用语法来声明它们。我发现这确实违反直觉。
我在这对结构上简化了我的愚蠢代码(一个引用另一个)。

#[derive(Debug, Default)]
pub struct TestStructA {
    pub byte_1: u8,
    pub byte_2: u8,
    pub vector: Vec<u8>,
}

impl<'a> Default for &'a TestStructA {
    fn default() -> &'a TestStructA {
        &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
    }
}

#[derive(Debug, Default)]
pub struct TestStructB<'a> {
    pub test_array: &'a [u8],
    pub t_a: &'a TestStructA,
}
如果将此隔离的代码复制并粘贴到main.rs文件中并进行编译,则将出现以下错误:
error: expected `while`, `for`, `loop` or `{` after a label
  --> src/main.rs:10:59
   |
10 |         &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
   |                                                           ^^^ expected `while`, `for`, `loop` or `{` after a label

error: labeled expression must be followed by `:`
  --> src/main.rs:10:59
   |
10 |         &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
   |                                                        ---^^^^^^^^^^^^^
   |                                                        | |
   |                                                        | help: add `:` after the label
   |                                                        the label
   |
   = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
如果不注释矢量参数的生存期,则会得到预期的结果:“检查您的生存期男孩”(这很有意义)。
error[E0515]: cannot return reference to temporary value
  --> src/main.rs:10:9
   |
10 |         &TestStructA { byte_1: 10, byte_2: 20, vector: vec![1, 2, 3] }
   |         ^-------------------------------------------------------------
   |         ||
   |         |temporary value created here
   |         returns a reference to data owned by the current function
当然,如果我选择一个更严格的解决方案来从我的结构中删除“vector”属性,因为所有其他属性都是标量,则代码会编译。但是我需要我的结构具有某种非标量数据结构。我怀疑我的默认初始化程序中的向量需要某种生命周期标签,但我不确定是什么
顺便说一句,我认为我的TestStructB也正确地标注了生命周期,但也许没有。看起来正确吗?
最后,我到达这里是因为编译器说我需要为原始结构的引用(&)版本声明一个Default初始化程序。这个原始结构已经在我的程序中愉快地使用过,但是从未被引用过。每当我开始以引用方式使用它时,Rust都声称它需要其Default初始化程序。问题是,我仍然有些觉得使用引用的Struct时做错了什么,并且有一种正确的方法来使用&referenced(且带有生命周期注释)的结构,而Rust不会提示它们的(不存在的)默认初始化器。
编辑:@JohnKugelman绝对是正确的,在典型的新手与rust编译器进行斗争以试图克服它产生的主要隐秘消息之后,我就谈到了这种“畸变”。
我的简化原文是:
#[derive(Debug, Default)]
pub struct TestStructA {
    pub byte_1: u8,
    pub byte_2: u8,
    pub vector: Vec<u8>,
}

#[derive(Debug, Default)]
pub struct TestStructB<'a> {
    pub test_array: &'a [u8],
    pub t_a: &'a TestStructA,
}
有了这段代码,我得到的错误是:
error[E0277]: the trait bound `&TestStructA: Default` is not satisfied
  --> src/main.rs:11:5
   |
11 |     pub t_a: &'a TestStructA,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&TestStructA`
   |
   = help: the following implementations were found:
             <TestStructA as Default>
   = note: required by `std::default::Default::default`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
显然rustc误导了我以为我需要&Struct默认初始值设定项?不能说...

最佳答案

出现非常规要求的原因是,您正在尝试为包含引用的Default结构实现TestStructB。在大多数情况下,Default用于具有所有拥有的值或可以某种方式为空的类型。
为了为引用Default实现&'a TestStructA,您将必须具有Default::default实现可以返回引用的类型的常量或泄漏值-基本上需要&'static TestStructA
如果向量为空,这很容易做到,因为Vec::new()const fn,因此我们可以构造TestStructA的完整编译时常数实例:

impl<'a> Default for &'a TestStructA {
    fn default() -> &'a TestStructA {
        static VALUE: TestStructA = TestStructA {
            byte_1: 10,
            byte_2: 20,
            vector: Vec::new()
        };
        &VALUE
    }
}
如果要在向量中包含一些数据,则必须使用像 once_cell 这样的惰性初始化机制才能执行vec!来分配向量的内容,然后返回对其的引用。
use once_cell::sync::Lazy;

static DEFAULT_A: Lazy<TestStructA> = Lazy::new(|| {
    TestStructA {byte_1: 10, byte_2: 20, vector: vec![1, 2, 3]}
});

impl<'a> Default for &'a TestStructA {
    fn default() -> &'a TestStructA {
        &DEFAULT_A
    }
}
如果要执行此操作,我建议您也实现Default for TestStructA,因为对于引用有Default而不是拥有的值很奇怪。
impl Default for TestStructA {
    fn default() -> TestStructA {
        DEFAULT_A.clone()
    }
}
(这仅在TestStructA也实现Clone的情况下有效,但可能应该这样做。如果不这样做,则将struct文字放入TestStructA::default方法中,并将DEFAULT_A定义为Lazy::new(TestStructA::default)。)
但是,所有这些详细信息仅是必要的,因为
  • 您正在为Default
  • 实现TestStructB
  • 始终包含对TestStructA的引用。

  • 您应考虑在默认情况下TestStructB是否实际上需要此引用-例如,如果t_a的类型为Option<&'a TestStructA>,则它可以默认为None。我没有足够的信息来说明这是否适合您的应用程序-根据这些结构的确切用途做出自己的选择。

    关于struct - 如何为&Struct实现Default?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66609014/

    相关文章:

    rust - 创建 Vec 时,借用的值不够长

    c - Doxygen 文档结构成员与属性

    c - C `=` 运算符在结构之间应用时是否复制内存?

    hash - 如何从 Rust 中的 Blake2 crate 返回结果?

    rust - 自定义迭代器中可变引用的生命周期参数问题

    rust - 如何声明一个比其封闭 block 生命周期更长的闭包

    C++结构,新类型之间的区别;和新类型()

    c - 指向存储在结构中的数组的指针

    rust - 有没有办法将基准测试结果保存为 JSON?

    rust - 将数组从 Rust 返回到 FFI