我有一个程序,或多或少看起来像这样
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)
另外,如果你不希望有任何的Clone或Copy界限,那么你就可以改变你的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为你自己的类型实现.