【问题标题】:Is the order in which struct fields are initialized guaranteed in Rust?Rust 中是否保证了初始化结构字段的顺序?
【发布时间】:2020-09-11 01:25:25
【问题描述】:

我在Constructors - The Rustonomicon 中找不到对此的任何引用。是不是保证下面的代码……

struct Mutates {
    n: usize,
}

impl Mutates {
    fn side_effects(&mut self) -> usize {
        self.n += 1;
        self.n
    }
}

#[derive(Debug)]
struct Struct {
    a: usize,
    b: usize,
}

fn main() {
    let mut m = Mutates { n: 0 };

    // note the order of the fields
    dbg!(Struct {
        a: m.side_effects(),
        b: m.side_effects(),
    });
    dbg!(Struct {
        b: m.side_effects(),
        a: m.side_effects(),
    });
}

...总是会打印以下内容?

[src/main.rs:22] Struct{a: m.side_effects(), b: m.side_effects(),} = Struct {
    a: 1,
    b: 2,
}
[src/main.rs:26] Struct{b: m.side_effects(), a: m.side_effects(),} = Struct {
    a: 4,
    b: 3,
}

或者编译器是否可以分配不同的值?

请注意,问题是关于字段初始化而不是声明的顺序。

请注意,此问题专门询问 structs 而不是元组,What is the evaluation order of tuples in Rust? 已回答。

【问题讨论】:

标签: struct rust initialization


【解决方案1】:

是的,这是有保证的。 Ralf Jungcompiler team contributor 在 Zulip 上确认:

结构体字段的初始化顺序是否有保证?

拉尔夫:

是的 - 它始终是您在初始化程序中写入字段的顺序

结构定义中字段的顺序无关

【讨论】:

  • 谢谢,但我希望有更官方的声明(例如,RFC 或在书中或书的某处提及)。对我来说,即使是像拉尔夫这样重要的人发出的聊天消息,也没有适当的官方参考那么有价值。
【解决方案2】:

是的,因为更改它将是一个重大更改:

struct Foo(usize);

impl Foo {
    fn make_val(&mut self) -> usize {
        self.0 + 20
    }
}

struct Bar {
    a: Foo,
    b: usize,
}

let mut foo = Foo(10); // Not copy or clone.
// let bar = Bar {        //Wouldn't work since `foo` is moved into a.
//     a: foo,
//     b: foo.make_val(),
// };

let bar = Bar {
    b: foo.make_val(),
    a: foo,
}

我们还可以观察到,实例化端的字段顺序改变了值在语义上构建的顺序。 Playground.

#![allow(dead_code)]
struct Bar;
impl Bar {
    pub fn new(val: usize) -> Self {
        println!("Making {}", val);
        Bar
    }
}

struct Foo {
    a: Bar,
    b: Bar,
    c: Bar,
}

fn main() {
    Foo {
        a: Bar::new(0),
        c: Bar::new(1),
        b: Bar::new(2),
    };
}

打印出来的

Making 0
Making 1
Making 2

【讨论】:

  • 您声称“更改它将是一个重大更改”,这是否记录在书或书的任何地方? (或者它是过去记录的?)也许有一个 RFC 解释这个?
  • @Lonami 官方的说法是,Rust 不会引入重大更改。因此,如果更改这将被视为当前版本中的重大更改,那么它不会发生。
  • @trentcl 我的观点是,如果它没有在任何地方定义,人们可能会在他们不应该依赖它的地方依赖它,我想看看它是在哪里定义的。我可以看到这将是一个重大更改,但除了作为实现细节之外,我看不到记录在哪里。例如,Heptametrical 的回答引用了编译器团队的贡献者,而不仅仅是声称代码会中断。
  • @Lonami 如果您不认为“无重大更改”是足够强大的保证,那么更明确的意义何在?换句话说,如果你不相信 Rust 开发团队会遵守他们的承诺以避免总体上的破坏性更改,那么如果他们承诺不做出这个特定的事情会有什么不同呢? 重大变化?我认为编写文档来列出所有可能的重大更改只是为了说“这些都是我们承诺不会做的事情”,我认为没有任何价值。
  • 无论如何,由于评估顺序似乎没有正式记录在任何地方,我认为这是目前最好的答案。
【解决方案3】:

lurking 通过 Rust 的问题之后,我遇到了 rust-lang/reference - Document expression evaluation order,它链接到 IRLO thread on Rust expression order of evaluation,其中 user fweimer posts

关于评估顺序的当前状态是什么?这个很 很想写这个:

struct Item {
    a: u32,
    b: u32,
}

impl Item {
    fn receive_word(&mut self) -> Result<u32, Error> {
        …
    }

    fn receive(&mut self) -> Result<Item, Error> {
        Ok(Item {
            a: self.receive_word()?,
            b: self.receive_word()?,
        })
    }
}

期望是首先收到值a,然后是值 湾。但是对于不确定的评估顺序,必须引入 临时工。

nikomatsakis responds

该代码是正确的,它不可能改变。事实上,我或多或少认为船已经航行关于改变评估顺序,期间。

还有soon after adds:

更重要的是,在结构字面量中,字段按照您编写它们的顺序进行评估;如果在结构完全构建之前发生恐慌,则中间值会以相反的顺序删除(一旦结构完全构建,字段将按照它们在结构声明中的写入顺序被删除,iirc)。

这增加了我正在寻找的“官方声明”,类似于 Heptamerical 的答案。

【讨论】:

    【解决方案4】:

    Rust 参考文献here 中记录了这一点:

    采用多个操作数的表达式按照源代码中的说明从左到右进行计算。

    这明确包括结构表达式。文档 PR 是 https://github.com/rust-lang/reference/pull/888,它关闭了 Lonami 的回答中提到的问题 https://github.com/rust-lang/reference/issues/248

    【讨论】:

    • 这是一个不相关的问题,但您能否看看我的question 关于 ECMAScript 词法语法中的多个目标符号?我在 esdiscuss 档案中看到了这个thread,所以希望你能有所了解。
    • 对于该问题的现有答案,我真的没有什么要补充的。事后看来,我后悔一直为 ES5 的标准化做出贡献。当时它似乎很有用,但我本可以做一些更有用的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 1970-01-01
    • 1970-01-01
    • 2016-04-16
    相关资源
    最近更新 更多