作为参数传递的引用不会移动

时间:2015-01-16 16:21:10

标签: rust

fn t(x: &mut u8) -> &mut u8 {
    x
}

fn main() {
    let mut x = 5u8;
    let y = & mut x;
    let z = t(y);
    println!("{}", y);
}

编译这个会给我这个错误:

main.rs:9:20: 9:21 error: cannot borrow `y` as immutable because `*y` is also borrowed as mutable
main.rs:9     println!("{}", y);

我原以为y会在致电t然后又回到z时被移动,从而产生error: use of moved value

  1. 为什么我会收到此错误消息?
  2. 当引用作为函数参数提供时,Rust会自动创建新的借用而不是传递所有权吗?
  3. 这种行为的目的是什么?

2 个答案:

答案 0 :(得分:3)

您正在从函数返回对参数的可变引用。但是,Rust并不知道方法没有保留该指针的副本没有返回该指针的子部分,如果它是一个结构。这意味着在任何时候,指向的值都可能会改变,这在Rust中是一个很大的禁忌;如果它被允许,那么你很容易导致内存错误。

  

Rust会自动创建新借用

是的,Rust"重新借用"引用。

一个更好的例子需要更复杂的微笑:

struct Thing { a: u8, b: u8 }

fn t(x: &mut Thing) -> &mut u8 {
    &mut x.a
}

fn main() {
    let mut x = Thing { a: 5, b: 6 };
    let z = t(&mut x);
    *z = 0;
    // x.a = 0; // cannot assign to `x.a` because it is borrowed
}

这里,t返回一个指向struct子集的可变指针。这意味着整个结构被借用了,我们无法改变它(除了通过z)。 Rust将此逻辑应用于所有函数,并且不会尝试识别您的t函数只返回相同的指针。

答案 1 :(得分:0)

通过使用rustc --pretty=expanded编译程序,我们可以看到println!宏借用了它的参数:

#![no_std]
#[macro_use]
extern crate "std" as std;
#[prelude_import]
use std::prelude::v1::*;
fn t(x: &mut u8) -> &mut u8 { x }

fn main() {
    let mut x = 5u8;
    let y = &mut x;
    let z = t(y);
    ::std::io::stdio::println_args(::std::fmt::Arguments::new({
                                                                  #[inline]
                                                                  #[allow(dead_code)]
                                                                  static __STATIC_FMTSTR:
                                                                         &'static [&'static str]
                                                                         =
                                                                      &[""];
                                                                  __STATIC_FMTSTR
                                                              },
                                                              &match (&y,) { // <----- y is borrowed here
                                                                   (__arg0,)
                                                                   =>
                                                                   [::std::fmt::argument(::std::fmt::String::fmt,
                                                                                         __arg0)],
                                                               }));
}