作为参数传递的引用未移动

Reference passed as parameter is not moved

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. 这种行为的目的是什么?

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

Does Rust automatically create a new borrow

是的,Rust "re-borrows" 参考文献。

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

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 return 是指向结构子集的可变指针。这意味着整个结构都是借用的,我们无法更改它(除了通过 z)。 Rust 将此逻辑应用于所有函数,并且不会尝试识别您的 t 函数只是 return 相同的指针。

通过使用 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)],
                                                               }));
}