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

时间:2015-02-18 22:20:15

标签: 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);
}

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

这个例子非常好用。现在,当我们将main的内容设为通用时,它就不再起作用了。

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

然后我收到以下错误:

  

错误:无法摆脱借来的内容

     

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

我不完全确定为什么会这样。有人可以向我解释为什么在Test<i32>期间拨打get_first时借用Test<T>是不是?

1 个答案:

答案 0 :(得分:10)

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

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

因此,给Copy T: Clone约束是非常有限的。限制较少的界限是CloneCopy特征类似于String(因为它复制了值),但它通常不仅仅是“复制位”。例如,Clone类型将通过为底层内存创建新的堆分配来实现generic_main

这需要您更改fn generic_main<T: Clone>(t: Test<T>) { let x = t.get_first(); t.do_something_with_x(x.clone()); } 的撰写方式:

Clone

或者,如果您不想拥有Copydo_something_with_x范围,则可以更改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); }

Copy

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