是否可以使用EntryAPI通过a获取值AsRef<str>,但是将其插入Into<String>?
这是工作示例:
use std::collections::hash_map::{Entry, HashMap};
struct Foo;
#[derive(Default)]
struct Map {
map: HashMap<String, Foo>,
}
impl Map {
fn get(&self, key: impl AsRef<str>) -> &Foo {
self.map.get(key.as_ref()).unwrap()
}
fn create(&mut self, key: impl Into<String>) -> &mut Foo {
match self.map.entry(key.into()) {
Entry::Vacant(entry) => entry.insert(Foo {}),
_ => panic!(),
}
}
fn get_or_create(&mut self, key: impl Into<String>) -> &mut Foo {
match self.map.entry(key.into()) {
Entry::Vacant(entry) => entry.insert(Foo {}),
Entry::Occupied(entry) => entry.into_mut(),
}
}
}
fn main() {
let mut map = Map::default();
map.get_or_create("bar");
map.get_or_create("bar");
assert_eq!(map.map.len(), 1);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,总是会创建get_or_create一个String遗嘱,导致不必要的内存分配,即使占用的条目不需要它.是否有可能以任何方式解决这个问题?也许以一种整洁的方式Cow?
在夜间 Rust 中,您可以使用不稳定的raw_entry_mut()功能来实现这一点:
为 HashMap 创建一个原始条目构建器。
[...]
原始条目对于诸如以下奇特情况很有用:
- 推迟创建拥有的密钥,直到知道需要它
在稳定的 Rust 中,您可以添加具有相同 API 但稳定的hashbrown crate。hashbrown crate 实际上是标准库 hashmap 的底层实现。
例子:
#![feature(hash_raw_entry)]
use std::collections::HashMap;
#[derive(Hash, PartialEq, Eq, Debug)]
struct NoCopy {
foo: i32,
}
impl Clone for NoCopy {
fn clone(&self) -> Self {
println!("Clone of: {:?}", self);
Self { foo: self.foo }
}
}
fn main() {
let no_copy = NoCopy { foo: 21 };
let mut map = HashMap::new();
map.raw_entry_mut()
.from_key(&no_copy)
.or_insert_with(|| (no_copy.clone(), 42));
map.raw_entry_mut()
.from_key(&no_copy)
.or_insert_with(|| (no_copy.clone(), 84));
println!("{:#?}", map);
}
Run Code Online (Sandbox Code Playgroud)
应用于您的原始示例:
fn get_or_create<K>(&mut self, key: K) -> &mut Foo
where
K: AsRef<str> + Into<String>,
{
self.map
.raw_entry_mut()
.from_key(key.as_ref())
.or_insert_with(|| (key.into(), Foo))
.1
}
Run Code Online (Sandbox Code Playgroud)
你不能,安全.这是当前条目API的限制,并没有很好的解决方案.
也可以看看:
对于非entry基于解决方案,请参阅: