我有一个函数为int执行:
fn some_to_value(src: Option<&int>) -> Option<int> {
match src {
Some(x) => Some(*x),
None => None
}
}
我想让它变得通用(并且仍然使用&#34; int&#34;在调用者级别)。如果复制T的实例,对我来说没问题。所以我尝试了这个:
fn some_to_value<T>(src: Option<&T>) -> Option<T> {
match src {
Some(x) => Some(*x),
None => None
}
}
我明白了:
error: cannot move out of dereference of `&`-pointer
Some(x) => Some(*x),
^~
我无法理解为什么会失败(我是初学者)。
某些背景:我制作了一个选项的副本,因为我意识到在做完&#34;找到&#34;在&#34; HashMap&#34;上,只要返回&#34;找到&#34;地图就是不可变的。 (包含对地图项目的引用的选项)是活着的。
答案 0 :(得分:3)
Rust语言具有强烈的所有权概念,这导致了"move vs. copy"场景(我将使用该答案中的术语)。
共享引用&T
(通常)是内存中某处T
的只读视图。一个重要的属性是,您不允许T
无效:&T
必须始终指向有效的T
实例。
当你写*x
时,你试图将T
移出值,因为T
是一个无界的泛型,编译器必须假设最坏的:类型T
不是Copy
因此必须移动所有权,也就是说,按值使用(也就是字节副本)不是语义副本,这意味着无法继续使用源代码(请参阅我的链接答案)有关此问题的更多解释)。移动所有权使源无效......但源位于&T
内,因此使其无效是非法的!
*x
适用于int
,因为它是Copy
,因此按值使用(也称为字节副本)与语义副本相同:&int
是没有失效。
答案 1 :(得分:2)
如果要允许复制T
,则必须告诉编译器。
您可以将T
的类型限制为Copy
类型的<{1}}:
只需复制位即可复制的类型(即memcpy)。
fn some_to_value<T: Copy>(src: Option<&T>) -> Option<T> {
match src {
Some(x) => Some(*x),
None => None
}
}
或者更通常地将T
限制为实现Clone
特征的类型:
fn some_to_value<T: Clone>(src: Option<&T>) -> Option<T> {
match src {
Some(x) => Some(x.clone()),
None => None
}
}
答案 2 :(得分:1)
Some(x) => Some(*x)
此代码采用x by值。在第一个函数中,x是一个int。像int这样的原语实现了Copy trait,这意味着它们在按值获取时会自动复制。将移动未实现Copy的类型。
您的通用功能并不保证T会实现复制。如果编译器让这个编译,你最终会得到一个取消引用x的函数,然后将基础数据复制或移动到输出选项中。移动会使原始内存位置无效!
您的通用函数将使用复制约束:some_to_value<T: Copy>
,以确保T将实现复制。
您可能希望该函数不仅仅使用基元,因此您必须使用克隆特征。 match语句也可以写成map
函数,它完全相同。
fn some_to_value<T: Clone>(src: Option<&T>) -> Option<T> {
src.map(|num| num.clone())
}
答案 3 :(得分:1)
Rust 1.0.0正是为此而引入了Option<&T>::cloned()
(您可以摆脱some_to_value
之类的实用程序包装器)。摘录自文档:
通过克隆选项的内容将
Option<&T>
映射到Option<T>
。
Rust 1.26还引入了Option<&mut T>::cloned()
。
Rust 1.35.0引入了Option<&T>::copied()
,用于将其限制为只能复制的类型;参见blog post announcing 1.35 on this。