【问题标题】:Cannot move out of borrowed content when borrowing a generic type借用泛型类型时无法移出借用内容
【发布时间】:2015-04-20 03:08:10
【问题描述】:

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

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 上调用一个借用一些值的方法。然后我们在同一个结构上调用另一个方法,传递之前获得的值。

这个例子工作得很好。现在,当我们将main 的内容设为泛型时,它就不再起作用了。

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

然后我得到以下错误:

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

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

我不完全确定为什么会这样。有人可以向我解释为什么在调用get_first 时不借用Test&lt;i32&gt;Test&lt;T&gt; 是借用吗?

【问题讨论】:

    标签: pointers rust


    【解决方案1】:

    简短的回答是 i32 实现了 Copy 特征,但 T 没有。如果你使用fn generic_main&lt;T: Copy&gt;(t: Test&lt;T&gt;),那么你的直接问题就解决了。

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

    因此,将T 绑定到Copy 是非常严格的。限制较少的界限是T: CloneClone trait 与 Copy 相似(因为它复制值),但它通常不仅仅通过“复制位”来完成。例如,String 类型将通过为底层内存创建新的堆分配来实现 Clone

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

    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

    impl<T> Test<T> {
        // other methods elided
    
        fn do_something_with_x(&self, x: &T) {
            // Irrelevant
        }
    }
    

    你的generic_main 基本保持不变,除了你没有取消引用x

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

    你可以阅读更多关于Copyin the docs的信息。有一些很好的例子,包括如何为你自己的类型实现Copy

    【讨论】:

    • “移动位”的使用有点令人困惑,因为 Rust 通过移动位来移动。也许“复制位”会更清楚?
    • @MatthieuM。当然。更新。对于它的价值,我直接从语言参考中提取了前面的措辞:'复制,对于“普通旧数据”类型,可以通过简单地移动位来复制。'
    • @BurntSushi5:有趣,也许我们应该警告 steve 比在“复制”上下文中使用“移动”有点混乱?
    猜你喜欢
    • 2018-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    • 2015-08-02
    相关资源
    最近更新 更多