我有一个或多或少看起来像这样的程序
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>
是不是?
答案 0 :(得分: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());
}
的撰写方式:
Clone
或者,如果您不想拥有Copy
或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
您可以阅读有关Copy
in the docs的更多信息。有一些很好的例子,包括如何为你自己的类型实现{{1}}。