转换选项&lt;&amp; T&gt;选项<t> </t>

时间:2014-06-27 20:53:11

标签: generics rust

我有一个函数为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;地图就是不可变的。 (包含对地图项目的引用的选项)是活着的。

4 个答案:

答案 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