首页 文章

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

提问于
浏览
5

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

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>Test<T>Test<T> 时没有借用?

1 回答

  • 10

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

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

    因此,给你的 T 约束是非常严格的 . 限制较少的界限是 T: Clone . Clone trait类似于 Copy (因为它复制值),但它通常不仅仅是"copying bits."完成 . 例如, 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 方法以引用 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 in the docs的更多信息 . 有一些很好的例子,包括如何为你自己的类型实现 Copy .

相关问题