Rust中有哪些规则,类似于规则,这里描述了{+ 3}}对于C ++?
现在我从经验上发现了那个
1)函数的参数按直接顺序进行评估
2)所有带副作用的内置操作(=,+ =, - =等)返回单位,因此很难(但可能)编写表达式,这将在C ++中显示UB。
一个例子:
let mut a = 1i;
let b = 2i;
let c = 3i;
let d = (a = b) == (a = c); // What is a? (a is actually 3)
3)似乎函数调用按照C ++中的顺序排序 4)似乎内置操作被排序,好像它们是函数(方法)调用,即评估顺序与运算符优先级相关
我的结论是否正确?什么是确切的评估模型?
答案 0 :(得分:5)
我不相信它已被明确定义,我对the manual的嘲讽没有发现任何事情。但是,我可以保证这些东西不会是未定义的行为(Rust明确地避免在unsafe
代码之外的UB),如果它不是“从左到右”,那么我会感到惊讶,也就是说,顺序你推断出来了。虽然,#6268的分辨率可能导致最后评估接收器的方法(或者可能不是,这只是一种可能性)。
我打开了#15300。
顺便说一下,如果你正在研究这个问题,你可以让编译器用精确评估顺序拆分出漂亮的控制流图(注意。这是所有内部API,因此不能依赖于,使编译器崩溃的可能性比正常情况高,并且不会隐藏编译器实现细节:它主要是为rustc
)工作的人设计的。
正如@pnkfelix指出的那样,编译器没有使用CFG进行代码生成(截至2014-07-02),这意味着CFG不能保证准确无误。 < / p>
E.g。以@ 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
是一个毫无意义的遗物:现在只在宏扩展后才分配ID):
#![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
(并且控制流程图确认在RHS之后正在评估LHS上的孤立a
,包括a = 3
那里。我在#15300( e:和现在isolated it to a strange difference in evaluation order)上提出了这个问题。