我不相信它已被明确定义,我对 the manual 的 grepping 没有发现任何东西。但是,我可以保证这些事情不会是未定义的行为(Rust 明确避免在 unsafe 代码之外使用 UB),如果它不是“从左到右”,即您拥有的顺序,我会感到惊讶推断。虽然,#6268 的解析可能会导致方法最后评估接收器(或者可能不是,这只是一种可能性)。
我打开了#15300。
顺便说一句,如果您正在调查此问题,您可以让编译器按照 精确 的评估顺序拆分出漂亮的控制流图(注意,这是所有内部 API,因此不能依赖,比正常情况更有可能使编译器崩溃,并且不会隐藏编译器实现细节:它主要是为在 rustc 工作的人设计的。
正如@pnkfelix 指出的那样,编译器没有使用 CFG 进行代码生成(截至 2014 年 7 月 2 日),这意味着不能保证 CFG 完全准确。
例如采用@ChrisMorgan 的示例之一的精简版:
fn foo(_: (), x: int) -> int {
x
}
fn main() {
let mut a = 1;
{ // A
a * foo(a = 3, a)
};
}
我们希望编译器在某个块(即{ ... })中拆分出语句/表达式的控制流图,这可以通过编译器的--pretty flowgraph=<nodeid> 选项来完成,但为此我们需要我们感兴趣的区块的 ID。在这种情况下,我们想要的块是A。要使用rustc --pretty expanded,identified 编译id(注意,只使用identified 是毫无意义的遗物:ids 现在只在宏扩展后分配):
#![feature(phase)]
#![no_std]
#![feature(globs)]
#[phase(plugin, link)]
extern crate std = "std#0.11.0-pre";
extern crate native = "native#0.11.0-pre";
use std::prelude::*;
fn foo(_ /* pat 7 */: (), x /* pat 11 */: int) -> int { (x /* 15 */) } /*
block 14 */ /* 4 */
fn main() {
let mut a /* pat 22 */ = (1 /* 23 */);
({
((a /* 28 */) *
((foo /* 30
*/)(((a /* 32 */) = (3 /* 33 */) /* 31 */), (a /* 34 */)) /*
29 */) /* 27 */)
} /* block 26 */ /* 25 */);
} /* block 18 */ /* 16 */
很多讨厌的内部垃圾,但我们需要的东西在评论/* block 26 */ 中。 rustc --pretty flowgraph=26 给出了一个点文件,它呈现如下。您可以查阅上面的标识符注释源,以准确了解每个表达式的含义(id = .. 位):
(抱歉冗长,显然这段代码没有分支,所以只是一长串操作。)
FWIW,该表达式的计算结果为 9,而我期待的是 3(并且控制流图确认 LHS 上的隔离 a 正在 RHS 之后进行评估,包括那里的 a = 3) .我在 #15300 上提出了这个问题(e: 现在是 isolated it to a strange difference in evaluation order)。