在不使用 Clone 特性的情况下从集合中获取价值
Getting value from a collection without using the Clone trait
是否可以从集合中获取一个值并对其应用一种只接受 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构造,
我提到这个是为了明确声明我没有
省略了我知道的任何方法。
Is it possible to get a value from a collection and apply a method to it which accepts only self
and not &self
?
一般来说,不,不是没有从collection中删除它。 collection 拥有该值。 take self
的方法想要在消耗所有权的同时转换项目,所以你必须转移所有权。
克隆或复制一个项目会创建一个具有新所有权的新项目,然后您可以将其赋予该方法。
在您的特定情况下,您几乎可以摆脱这个令人兴奋的where
条款:
where for<'a> &'a B: Into<i32>
除了 From<&i32>
没有为 i32
实现。你可以写一个 trait 来做你想做的事情:
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()
}
函数使用 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
特性处理,但该特性尚不存在。
是否可以从集合中获取一个值并对其应用一种只接受 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构造, 我提到这个是为了明确声明我没有 省略了我知道的任何方法。
Is it possible to get a value from a collection and apply a method to it which accepts only
self
and not&self
?
一般来说,不,不是没有从collection中删除它。 collection 拥有该值。 take self
的方法想要在消耗所有权的同时转换项目,所以你必须转移所有权。
克隆或复制一个项目会创建一个具有新所有权的新项目,然后您可以将其赋予该方法。
在您的特定情况下,您几乎可以摆脱这个令人兴奋的where
条款:
where for<'a> &'a B: Into<i32>
除了 From<&i32>
没有为 i32
实现。你可以写一个 trait 来做你想做的事情:
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()
}
函数使用 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
特性处理,但该特性尚不存在。