为什么Rust既有值调用又有引用调用?

时间:2016-04-12 01:52:26

标签: rust calling-convention

某些语言(如Haskell)不区分传值和传递引用。然后,编译器可以使用启发式近似地选择最有效的调用约定。一个启发式示例是针对Linux x64 ABI:如果参数的大小大于16个字节,则将指针传递给堆栈,否则传递寄存器中的值。

在Rust中同时保留传值和传递引用(当然不可变)的概念有什么好处,并强制用户选择?

如果看到值被修改,那么传递值是传递引用+副本的语法糖吗?

2 个答案:

答案 0 :(得分:9)

两件事:

  1. Rust会根据类似的启发式将某些按值传递的调用转换为pass-by-reference。
  2. 按值传递表示所有权转移,而按引用传递表示借入。这些是非常不同的,与您提出的asm级关注完全正交。
  3. 换句话说,在Rust中,这两种形式具有不同的语义。但是,这并不排除进行优化。

答案 1 :(得分:0)

[已修改:已将exampled更改为在发布模式下工作]

这不是语法糖,正如人们可以通过查看生成的代码看到的那样。

鉴于这些功能:

fn by_value(v: (u64, u64)) -> u64 {
  v.0 + v.1
}

fn by_ref(v: &(u64, u64)) -> u64 {
  v.0 + v.1
}

然后如果一个是另一个的语法糖,我们希望它们生成相同的汇编代码,或至少相同的调用约定。但实际上,我们发现by_refvrdi个寄存器中传递了rsi,而by_valuev中传递了指向rdi的指针{1}}注册并且必须遵循该指针来获取值:(see details,使用释放模式):

by_value:
  movq  8(%rdi), %rax
  addq  (%rdi), %rax
  retq

by_ref:
  leaq  (%rdi,%rsi), %rax
  retq