借用通用类型时无法移出借用的内容 [英] Cannot move out of borrowed content when borrowing a generic type
问题描述
我有一个或多或少看起来像这样的程序
I have a program that more or less looks like this
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
上调用借入一些值的方法.然后,我们在相同的结构上调用另一个方法,并传递先前获得的值.
Basically, we call a method on the struct Test
that borrows some value. Then we call another method on the same struct, passing the previously obtained value.
这个例子工作得很好.现在,当我们使main
的内容通用时,它将不再起作用.
This example works perfectly fine. Now, when we make the content of main
generic, it doesn't work anymore.
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;
src/main.rs:14 let raw_x = *x;
我不确定为什么会这样.有人可以向我解释为什么在Test<T>
通话时调用get_first
时为什么不借用Test<i32>
吗?
I'm not completely sure why this is happening. Can someone explain to me why Test<i32>
isn't borrowed when calling get_first
while Test<T>
is?
推荐答案
简短的答案是i32
实现了Copy
特征,而T
没有.如果使用fn generic_main<T: Copy>(t: Test<T>)
,则您的直接问题已解决.
The short answer is that i32
implements the Copy
trait, but T
does not. If you use fn generic_main<T: Copy>(t: Test<T>)
, then your immediate problem is fixed.
更长的答案是Copy
是一个特殊的特征,这意味着可以通过简单地复制位来复制值.像i32
这样的类型实现Copy
.像String
这样的类型不会实现 ,因为例如,它需要堆分配.如果仅通过复制位来复制String
,则最终会得到两个String
值,它们指向相同的内存块.那样不好(不安全!).
The longer answer is that Copy
is a special trait which means values can be copied by simply copying bits. Types like i32
implement Copy
. Types like String
do not implement Copy
because, for example, it requires a heap allocation. If you copied a String
just by copying bits, you'd end up with two String
values pointing to the same chunk of memory. That would not be good (it's unsafe!).
因此,给您的T
一个Copy
限制是非常严格的.较少限制的边界将是T: Clone
. Clone
特性与Copy
类似(因为它复制值),但是通常不仅仅是复制位"来完成.例如,String
类型将通过为基础内存创建新的堆分配来实现Clone
.
Therefore, giving your T
a Copy
bound is quite restrictive. A less restrictive bound would be T: Clone
. The Clone
trait is similar to Copy
(in that it copies values), but it's usually done by more than just "copying bits." For example, the String
type will implement Clone
by creating a new heap allocation for the underlying memory.
这需要您更改generic_main
的书写方式:
This requires you to change how your generic_main
is written:
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
方法以将 reference 用作T
而不是拥有的T
:
Alternatively, if you don't want to have either the Clone
or Copy
bounds, then you could change your do_something_with_x
method to take a reference to T
rather than an owned T
:
impl<T> Test<T> {
// other methods elided
fn do_something_with_x(&self, x: &T) {
// Irrelevant
}
}
您的generic_main
基本上保持不变,除了您不取消引用x
:
And your generic_main
stays mostly the same, except you don't dereference x
:
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x);
}
您可以在文档中阅读有关Copy
> 的更多信息.有一些不错的示例,包括如何为自己的类型实现Copy
.
You can read more about Copy
in the docs. There are some nice examples, including how to implement Copy
for your own types.
这篇关于借用通用类型时无法移出借用的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!