在不使用克隆特征的情况下从集合中获取价值

时间:2016-03-08 17:03:37

标签: rust readonly move-semantics traits

是否可以从集合中获取值并将方法应用于仅接受self而不是&self的方法?

最小工作示例

我想写的是类似于:

use std::collections::HashMap;

fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
    let v: &Vec<(i32, B)> = h.get(&key).unwrap();
    let val: &B = v.first().unwrap().1;

    // Do something to be able to call into
    // I only need the value as read-only
    // Does B have to implement the Clone trait?
    return val.into();
}

我试图在编译器出错后尝试安装mut以试图安抚编译器错误,但这实在是徒劳无功。

use std::collections::HashMap;

fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
    let mut v: &Vec<(i32, B)> = h.get_mut(&key).unwrap();
    let ref mut val: B = v.first_mut().unwrap().1;
    return (*val).into();
}

这种事情是否可能或B必须实施Clone特征?

我也尝试过:

  • 不安全
  • 原始指针

我没试过:

  • Box
  • 我没有遇到的其他Rust构造, 我提到这一点,明确表示我没有 省略了我所知道的任何方法。

2 个答案:

答案 0 :(得分:3)

  

是否可以从集合中获取值并将方法应用于仅接受self而不是&self的方法?

一般来说,不,不是没有从集合中删除它。该集合拥有该值。使self想要在消费所有权的同时转换项目的方法,因此您必须转移所有权。

克隆或复制项目会创建一个具有新所有权的新项目,然后您可以将该项目提供给该方法。

在您的特定情况下,您可以几乎逃脱这个令人兴奋的where条款:

where for<'a> &'a B: Into<i32>

From<&i32>未实现i32除外。你可以写一个能做你想要的特性:

use std::collections::HashMap;

trait RefInto<T> {
    fn into(&self) -> T;
}

impl RefInto<i32> for i32 {
    fn into(&self) -> i32 { *self }
}

fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32
    where B: RefInto<i32>
{
    let v = h.get(&key).unwrap();
    let val = &v.first().unwrap().1;

    val.into()
}

// ----

fn main() {
    let mut map = HashMap::new();
    map.insert(42, vec![(100, 200)]);
    let v = get(42, map);
    println!("{:?}", v);
}

或者,您可以使用Borrow

use std::collections::HashMap;
use std::borrow::Borrow;

fn get<B>(key: i32, h: HashMap<i32, Vec<(i32, B)>>) -> i32
    where B: Borrow<i32>
{
    let v = h.get(&key).unwrap();
    let val = &v.first().unwrap().1;

    *val.borrow()
}

答案 1 :(得分:1)

该功能使用HashMap。我假设这是你的意图,因此你不关心它的任何内容,除了你希望转换为i32的一个元素。

您可以使用HashMap::remove方法提取值。然后,您可以使用Vec::swap_remove来提取第一个元素。

use std::collections::HashMap;

fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> i32 where B: Into<i32> {
    h.remove(&key)
        .unwrap()
        .swap_remove(0)
        .1
        .into()
}

如果B复制起来很便宜,那么编写复制它的函数会更有意义。

以上不处理错误。具有错误处理的版本可能如下所示:

use std::collections::HashMap;

fn get<B>(key: i32, mut h: HashMap<i32, Vec<(i32, B)>>) -> Option<i32> where B: Into<i32> {
    h.remove(&key)
        .and_then(|mut vec| {
            if vec.is_empty() { None } 
            else { Some(vec.swap_remove(0).1.into()) }
        })
}

Vec::swap_remove并不理想。将任意索引处的元素移出向量而不进行任何其他工作的功能将由IndexMove特征处理,但该特征尚不存在。