借用泛型类型时,无法摆脱借来的内容

NSA*_*ict 5 pointers rust

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

这个例子非常好用.现在,当我们制作main泛型的内容时,它不再起作用了.

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

然后我收到以下错误:

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

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

我不完全确定为什么会这样.有人可以向我解释为什么Test<i32>在打电话get_first时不借用Test<T>

Bur*_*hi5 10

简短的回答是i32实现Copy特性,但T没有.如果您使用fn generic_main<T: Copy>(t: Test<T>),那么您的问题就解决了.

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

因此,给你T一个Copy限制是非常严格的.限制较少的界限是T: Clone.该Clone特性是相似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());
}
Run Code Online (Sandbox Code Playgroud)

另外,如果你不希望有任何的CloneCopy界限,那么你就可以改变你的do_something_with_x方法取一个参考T,而不是一个拥有T:

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

    fn do_something_with_x(&self, x: &T) {
        // Irrelevant
    }
}
Run Code Online (Sandbox Code Playgroud)

generic_main除了你没有取消引用外,你的住宿大致相同x:

fn generic_main<T>(t: Test<T>) {
    let x = t.get_first();
    t.do_something_with_x(x);
}
Run Code Online (Sandbox Code Playgroud)

您可以Copy 在文档中阅读更多相关信息.有一些很好的例子,包括如何Copy为你自己的类型实现.