借用泛型时无法移出借用的内容
Cannot move out of borrowed content when borrowing a generic type
我有一个大致像这样的程序
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);
}
基本上,我们在结构 Test
上调用一个借用一些值的方法。然后我们在同一个结构上调用另一个方法,传递之前获得的值。
这个例子工作得很好。现在,当我们将 main
的内容设为通用时,它就不再起作用了。
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
然后我得到以下错误:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
我不完全确定为什么会这样。有人可以向我解释为什么在调用 get_first
时没有借用 Test<i32>
而 Test<T>
是借用的吗?
简短的回答是 i32
实现了 Copy
特性,但 T
没有。如果您使用 fn generic_main<T: Copy>(t: Test<T>)
,那么您眼前的问题就解决了。
较长的答案是 Copy
是一个特殊特征,这意味着可以通过简单地复制位来复制值。 i32
等类型实现了 Copy
。像 String
这样的类型 而不是 实现 Copy
因为,例如,它需要堆分配。如果你只是通过复制位来复制 String
,你最终会得到两个指向同一内存块的 String
值。那可不好(不安全!)。
因此,给您的 T
一个 Copy
限制是非常严格的。限制较少的界限是 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());
}
或者,如果您不想使用 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
in the docs 的更多信息。有一些很好的示例,包括如何为您自己的类型实现 Copy
。
我有一个大致像这样的程序
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);
}
基本上,我们在结构 Test
上调用一个借用一些值的方法。然后我们在同一个结构上调用另一个方法,传递之前获得的值。
这个例子工作得很好。现在,当我们将 main
的内容设为通用时,它就不再起作用了。
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
然后我得到以下错误:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
我不完全确定为什么会这样。有人可以向我解释为什么在调用 get_first
时没有借用 Test<i32>
而 Test<T>
是借用的吗?
简短的回答是 i32
实现了 Copy
特性,但 T
没有。如果您使用 fn generic_main<T: Copy>(t: Test<T>)
,那么您眼前的问题就解决了。
较长的答案是 Copy
是一个特殊特征,这意味着可以通过简单地复制位来复制值。 i32
等类型实现了 Copy
。像 String
这样的类型 而不是 实现 Copy
因为,例如,它需要堆分配。如果你只是通过复制位来复制 String
,你最终会得到两个指向同一内存块的 String
值。那可不好(不安全!)。
因此,给您的 T
一个 Copy
限制是非常严格的。限制较少的界限是 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());
}
或者,如果您不想使用 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
in the docs 的更多信息。有一些很好的示例,包括如何为您自己的类型实现 Copy
。