将可变引用的所有权重新传递给接受泛型类型的函数

时间:2018-01-08 03:29:32

标签: rust borrow-checker

为什么这段代码不能编译:

fn use_cursor(cursor: &mut io::Cursor<&mut Vec<u8>>) {
    // do some work
}

fn take_reference(data: &mut Vec<u8>) {
    {
        let mut buf = io::Cursor::new(data);

        use_cursor(&mut buf);
    }

    data.len();
}

fn produce_data() {
    let mut data = Vec::new();
    take_reference(&mut data);
    data.len();
}

这种情况下的错误是:

error[E0382]: use of moved value: `*data`
  --> src/main.rs:14:5
   |
9  |         let mut buf = io::Cursor::new(data);
   |                                       ---- value moved here
...
14 |     data.len();
   |     ^^^^ value used here after move
   |
   = note: move occurs because `data` has type `&mut std::vec::Vec<u8>`, which does not implement the `Copy` trait

io::Cursor::new的签名是这样的,它取得了参数的所有权,在这种情况下,参数是对Vec的可变引用。

pub fn new(inner: T) -> Cursor<T>

这对我来说很有意义;因为Cursor::new取得其参数的所有权(而不是引用),我们以后不能使用该值。同时它没有意义:我们基本上只传递一个可变引用,然后无论如何光标都超出了范围。 在produce_data函数中,我们还将可变引用传递给take_reference,并且在尝试再次使用data时不会产生错误,这与take_reference内部不同。

我发现可以使用Cursor.into_inner()'回收'引用,但手动执行它感觉有点奇怪,因为在正常使用情况下,借用检查器完全能够自行完成。

这个问题比使用.into_inner()有更好的解决方案吗?也许还有其他一些我对借用检查器不了解的东西?

1 个答案:

答案 0 :(得分:5)

通常,当您将可变引用传递给函数时,编译器会隐式执行 reborrow 。这会产生一个寿命更短的新借用。

当参数是通用的(并且不是&mut T形式)时,编译器不会自动进行此重新解释。但是,您可以通过取消引用现有的可变引用并再次引用它来手动执行此操作:

fn take_reference(data: &mut Vec<u8>) {
    {
        let mut buf = io::Cursor::new(&mut *data);

        use_cursor(&mut buf);
    }

    data.len();
}