Rust 保证结构字段的初始化顺序吗?

Is the order in which struct fields are initialized guaranteed in Rust?

我在 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,
}

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

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

请注意,此问题专门询问 结构 而不是元组, 已回答。

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

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

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

Is the order in which struct fields are initialized guaranteed?

拉尔夫:

yes -- it's always the order in which you write the fields in the initializer

the order of the fields in the struct definition is irrelevant

lurking through Rust's issues, I came across rust-lang/reference - Document expression evaluation order, which links to an IRLO thread on Rust expression order of evaluation where user fweimer posts之后:

What’s the current state regarding order of evaluation? It is very tempting to write this:

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()?,
        })
    }
}

The expectation is that first the value a is received, then the value b. But with a non-determinate evaluation order, one has to introduce temporaries.

nikomatsakis responds:

That code is correct and there is no chance it will change. In fact, I’m more or less of the opinion that the ship has sailed with respect to making changes to order of evaluation, period.

soon after adds

More to the point, in a struct literal, the fields are evaluated in the order you write them; if a panic occurs before the struct is completely build, the intermediate values are dropped in the reverse order (once the struct is fully built, the fields are dropped in the order they are written in the struct declaration, iirc).

这增加了我正在寻找的 "official statement",类似于 Heptamerical 的答案。

Rust 参考文献 here 中记载:

Expressions taking multiple operands are evaluated left to right as written in the source code.

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