我有一个或多或少看起来像这样的程序
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 回答
简短的回答是
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
的编写方式:或者,如果您不想拥有
Clone
或Copy
边界,那么您可以更改do_something_with_x
方法以引用T
而不是拥有T
:并且你的
generic_main
大致保持不变,除非你没有取消引用x
:您可以阅读有关
Copy
in the docs的更多信息 . 有一些很好的例子,包括如何为你自己的类型实现Copy
.