Rust:通过引用自动传递

时间:2014-02-05 10:54:34

标签: rust

Rust教程经常提倡使用

fn myFunc( x : &Something ) -> ....

通过引用传递参数。这使得在调用网站上显然需要明确地获取值参考:

myFunc(&myValue).

但我查了一下,可以使用模式匹配中常用的'ref'关键字来做:

fn myFunc( ref x : Something ) -> ....

然后,我可以简单地通过

来调用它
myFunc(myValue)

内存方面,这是否像我预期的那样工作,或者在调用myFunc之前将myValue复制到堆栈上然后获取对副本的引用?

4 个答案:

答案 0 :(得分:12)

复制该值,然后引用该副本。

fn f(ref mut x: int) {
    *x = 12;
}

fn main() {
    let mut x = 42;
    f(x);
    println!("{:d}", x);
}

输出:42

答案 1 :(得分:5)

这两个函数都将x声明为&Something。不同的是,前者将引用或拥有的框作为参数,而后者则期望它是常规的堆栈值。举例说明:

struct Something;

fn by_reference(x: &Something) {
    println!("{:?}", x); // prints "&Something""
}

fn on_the_stack(ref x: Something) {
    println!("{:?}", x); // prints "&Something""
}

fn main() {
    let value_on_the_stack: Something = Something;
    let owned: ~Something = ~Something;
    let borrowed: &Something = &value_on_the_stack;

   // Compiles:
   on_the_stack(value_on_the_stack);

   // Fail to compile:
   // on_the_stack(owned);
   // on_the_stack(borrowed);

   // Dereferencing will do:
   on_the_stack(*owned);
   on_the_stack(*borrowed);

   // Compiles:
   by_reference(owned);
   by_reference(borrowed);

   // Fails to compile:
   // by_reference(value_on_the_stack);

   // Taking a reference will do:
   by_reference(&value_on_the_stack);
}

由于on_the_stack接受一个值,它会被复制,然后副本会与形式参数(示例中为ref x)中的模式匹配。该匹配将x绑定到对复制值的引用。

答案 2 :(得分:3)

如果您调用类似f(x)的函数,则x始终按值传递。

fn f(ref x: int) {
    // ...
}

相当于

fn f(tmp: int) {
    let ref x = tmp;
    // or,
    let x = &tmp;

    // ...
}

即。引用完全限于函数调用。

答案 3 :(得分:1)

如果该值未实现Copy,则两个函数之间的差异将变得更加明显。例如,Vec<T>并没有实现Copy,因为这是一个昂贵的操作,相反,它实现了Clone(需要特定的方法调用)。

假设这样定义了两种方法

fn take_ref(ref v: Vec<String>) {}// Takes a reference, ish
fn take_addr(v: &Vec<String>) {}// Takes an explicit reference

take_ref将尝试在引用之前复制传递的值。对于Vec<T>,这实际上是一个移动操作(因为它不会复制)。这实际上消耗了向量,这意味着以下代码将引发编译器错误:

let v: Vec<String>; // assume a real value
take_ref(v);// Value is moved here
println!("{:?}", v);// Error, v was moved on the previous line

但是,当引用是显式的时,如take_addrVec不会移动,而是通过引用传递。因此,此代码可以正常工作:

let v: Vec<String>; // assume a real value
take_addr(&v);
println!("{:?}", v);// Prints contents as you would expect