2016-03-08 39 views
4

是否有可能得到一个集合的值,并适用于它的一种方法,其只接受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
  • 其他防锈构造,我有未遇到, 我提到这一点,明确指出我没有删除任何我知道的方法。

回答

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

功能消耗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特征来处理,该特征虽然还不存在。

+0

我希望'HashMap'仍然将密钥与它具有的相同向量关联起来。 –

+2

@FilipAllberg A.B.的观点虽然非常重要。通过接受'h:HashMap',你可以将map *的所有权转移给函数*。这个函数对地图的作用基本没有关系,因为没有别的东西能够使用地图。 – Shepmaster

+0

注意到,现在使用'&h'。谢谢! –