gpt4 book ai didi

rust - 通用 HashMap 不实现方法 get

转载 作者:行者123 更新时间:2023-11-29 08:14:50 25 4
gpt4 key购买 nike

我正在尝试创建将包含大量通用类型化字段的通用结构。该结构的 AST 将由编译器插件生成,并将用于从模板渲染文本。

use std::collections::HashMap;
use std::string::ToString;


pub struct Context<Key, Value>
where Value: ToString
{
value: HashMap<Key, Value>,
// here will be other fields with different generic types
}


impl <Key, Value> Context <Key, Value>
where Value: ToString
{
// In Jinja2 this can be written like
// `some text before ... {{ value["foobar"] }} ... text after`
pub fn render_to_string(&self) -> String {
let mut r = String::new();
r.push_str("text before ... ");

// We see that the type of key is &'static str.
// It is easy to determine when code written manually by human.
// But such code will be generated by compiler plugin.
// Here can be integer or another field from &self
// instead of static string.
self.value.get(&("foobar")).map(|v: &Value| r.push_str(&v.to_string()));

r.push_str(" ... text after");
r
}
}


fn main() {
let ctx1 = Context {
value: {
let mut v = HashMap::new();
v.insert("foobar", 123u64);
v
},
};
println!("{:?}", ctx1.render_to_string());
}

不幸的是,Rust 拒绝编译具有这种模糊类型的代码,但它没有告诉应该为泛型定义哪些特征,而是输出:

<anon>:25:20: 25:36 error: type `std::collections::hash::map::HashMap<Key, Value>` does not implement any method in scope named `get`
<anon>:25 self.value.get(&("foobar")).map(|v: &Value| r.push_str(&v.to_string()));
^~~~~~~~~~~~~~~~

是否可以在不指定 KeyValue 的确切类型的情况下修复此代码?

最佳答案

让我们看看 type signature of get :

impl<K, V, S> HashMap<K, V, S>
where K: Eq + Hash,
S: HashState
{
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where K: Borrow<Q>,
Q: Hash + Eq
{}
}

对于 get,所有这些条件都必须为真方法可用。具体来说,在您的情况下,您需要 Key成为Eq + Hash :

impl <Key, Value> Context <Key, Value>
where Key: Eq + std::hash::Hash,
Value: ToString

这会导致一个新错误,因为您使用的是 &str作为获取的关键,所以你真的必须指定一个 &str 可以用作键:

impl<Key, Value> Context <Key, Value>
where Key: Eq + std::hash::Hash + std::borrow::Borrow<str>,
Value: ToString

然后,从您的 get 中删除引用行:

self.value.get("foobar")

So, path std::borrow::Borrow<str> strictly specifies that we know the real type of key at code generation stage.

指定您知道 key 的真实类型。它只需要无论您的 key 是什么,&str可以借一个&Key .例如,您的 Key可能是 StringCowString .这是必需的,因为您正在使用 "foobar"作为关键。

[The key] can be integer or another field from &self instead of static string.

如果它是 self 的另一个成员,那么您可以适本地参数化该结构:

use std::collections::HashMap;
use std::string::ToString;
use std::hash::Hash;

pub struct Context<Key, Value> {
value: HashMap<Key, Value>,
key: Key,
}

impl <Key, Value> Context <Key, Value>
where Key: Eq + Hash,
Value: ToString,
{
pub fn render_to_string(&self) -> String {
let mut r = "text before ... ".to_string();

self.value.get(&self.key).map(|v| r.push_str(&v.to_string()));

r.push_str(" ... text after");
r
}
}

fn main() {
let ctx1 = Context {
key: 42,
value: {
let mut v = HashMap::new();
v.insert(42, 123u64);
v
},
};
println!("{:?}", ctx1.render_to_string());
}

to force Rust to resolve key type at first self.value.get call

这听起来像是您想要动态(运行时)键入 - 这不存在。 Rust 是一种静态类型语言,因此必须在编译时确定类型。

如果您有一组固定的键类型,您可以简单地创建一个枚举:

enum Key {
String(String),
Int(i32),
}

然后使用它而不是通用的。

关于rust - 通用 HashMap 不实现方法 get,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28917594/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com