问题
Some languages, like Haskell, make no distinction between pass-by-value and pass-by-reference. The compiler can then approximately choose the most efficient calling convention with a heuristic. One example heuristic would be for the Linux x64 ABI: if the size of parameter is greater than 16 bytes, pass a pointer to the stack otherwise pass the value in registers.
What is the advantage of keeping both notions of pass-by-value and pass-by-reference (non-mutable of course) in Rust and forcing the user to choose?
Could it be the case that pass-by-value is syntactic sugar for pass-by-reference + copy if the value is seen to be modified?
回答1:
Two things:
- Rust will transform certain pass-by-value calls into pass-by-reference, based on a similar heuristic.
- Pass-by-value indicates ownership transfer, while pass-by-reference indicates borrowing. These are very different, and totally orthogonal from the asm-level concern you're asking about.
In other words, in Rust, these two forms have different semantics. That doesn't preclude also doing the optimization, though.
回答2:
[Edited: changed exampled to work in release mode]
It isn't syntactic sugar, as one can see by looking at the generated code.
Given these functions:
fn by_value(v: (u64, u64)) -> u64 {
v.0 + v.1
}
fn by_ref(v: &(u64, u64)) -> u64 {
v.0 + v.1
}
then if one was syntactic sugar for another, we'd expect them to generate identical assembly code, or at least identical calling conventions. But actually, we find that by_ref
passes v
in the rdi
and rsi
registers, whereas by_value
passes a pointer to v
in the rdi
register and has to follow that pointer to get the value: (see details, use release mode):
by_value:
movq 8(%rdi), %rax
addq (%rdi), %rax
retq
by_ref:
leaq (%rdi,%rsi), %rax
retq
来源:https://stackoverflow.com/questions/36562262/why-does-rust-have-both-call-by-value-and-call-by-reference