借用通用类型时无法移出借用的内容 [英] Cannot move out of borrowed content when borrowing a generic type

查看:108
本文介绍了借用通用类型时无法移出借用的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个或多或少看起来像这样的程序

I have a program that more or less looks like this

struct Test<T> {
    vec: Vec<T>
}

impl<T> Test<T> {
    fn get_first(&self) -> &T {
        &self.vec[0]
    }

    fn do_something_with_x(&self, x: T) {
        // Irrelevant
    }
}

fn main() {
    let t = Test { vec: vec![1i32, 2, 3] };
    let x = t.get_first();
    t.do_something_with_x(*x);
}

基本上,我们在结构Test上调用借入一些值的方法.然后,我们在相同的结构上调用另一个方法,并传递先前获得的值.

Basically, we call a method on the struct Test that borrows some value. Then we call another method on the same struct, passing the previously obtained value.

这个例子工作得很好.现在,当我们使main的内容通用时,它将不再起作用.

This example works perfectly fine. Now, when we make the content of main generic, it doesn't work anymore.

fn generic_main<T>(t: Test<T>) {
    let x = t.get_first();
    t.do_something_with_x(*x);
}

然后我得到以下错误:

错误:无法移出借用的内容

error: cannot move out of borrowed content

src/main.rs:14 let raw_x = * x;

src/main.rs:14 let raw_x = *x;

我不确定为什么会这样.有人可以向我解释为什么在Test<T>通话时调用get_first时为什么不借用Test<i32>吗?

I'm not completely sure why this is happening. Can someone explain to me why Test<i32> isn't borrowed when calling get_first while Test<T> is?

推荐答案

简短的答案是i32实现了Copy特征,而T没有.如果使用fn generic_main<T: Copy>(t: Test<T>),则您的直接问题已解决.

The short answer is that i32 implements the Copy trait, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>), then your immediate problem is fixed.

更长的答案是Copy是一个特殊的特征,这意味着可以通过简单地复制位来复制值.像i32这样的类型实现Copy.像String这样的类型不会实现 ,因为例如,它需要堆分配.如果仅通过复制位来复制String,则最终会得到两个String值,它们指向相同的内存块.那样不好(不安全!).

The longer answer is that Copy is a special trait which means values can be copied by simply copying bits. Types like i32 implement Copy. Types like String do not implement Copy because, for example, it requires a heap allocation. If you copied a String just by copying bits, you'd end up with two String values pointing to the same chunk of memory. That would not be good (it's unsafe!).

因此,给您的T一个Copy限制是非常严格的.较少限制的边界将是T: Clone. Clone特性与Copy类似(因为它复制值),但是通常不仅仅是复制位"来完成.例如,String类型将通过为基础内存创建新的堆分配来实现Clone.

Therefore, giving your T a Copy bound is quite restrictive. A less restrictive bound would be T: Clone. The Clone trait is similar to Copy (in that it copies values), but it's usually done by more than just "copying bits." For example, the String type will implement Clone by creating a new heap allocation for the underlying memory.

这需要您更改generic_main的书写方式:

This requires you to change how your generic_main is written:

fn generic_main<T: Clone>(t: Test<T>) {
    let x = t.get_first();
    t.do_something_with_x(x.clone());
}

或者,如果您不想具有CloneCopy界限,则可以更改do_something_with_x方法以将 reference 用作T而不是拥有的T:

Alternatively, if you don't want to have either the Clone or Copy bounds, then you could change your do_something_with_x method to take a reference to T rather than an owned T:

impl<T> Test<T> {
    // other methods elided

    fn do_something_with_x(&self, x: &T) {
        // Irrelevant
    }
}

您的generic_main基本上保持不变,除了您不取消引用x:

And your generic_main stays mostly the same, except you don't dereference x:

fn generic_main<T>(t: Test<T>) {
    let x = t.get_first();
    t.do_something_with_x(x);
}

您可以在文档中阅读有关Copy > 的更多信息.有一些不错的示例,包括如何为自己的类型实现Copy.

You can read more about Copy in the docs. There are some nice examples, including how to implement Copy for your own types.

这篇关于借用通用类型时无法移出借用的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆