我对此问题有一个后续问题:Expose a HashMap in a generic way that disregards the HashMap value
假设我要使用HashMapContainer
(在上一个问题的第一个答案中定义的那个)作为另一个结构(让我们称之为MyDB
)和MyDB
中的成员构造函数我想决定将该成员构造为HashMapContainerImpl1
还是HashMapContainerImpl2
。我不想将MyDB
定义为模板(例如MyDB<T>
),因为MyDB
用户并不关心HashMap
(MyDB
的值构造函数将对此做出决定)。正确的实现方式是什么?
这是我想要实现的示例代码(它不会编译):
pub trait HashMapContainer {
type Value;
fn get_hash_map(&self) -> &HashMap<String, Self::Value>;
fn get_hash_map_mut(&mut self) -> &mut HashMap<String, Self::Value>;
}
struct MyDB {
hash_container: HashMapContainer
}
impl MyDB {
pub fn new(hash_value_type: &str) -> MyDB {
// have a logic to set hash_container to either
// HashMapContainerImpl1 or HashMapContainerImpl2
// according to hash_value_type
}
pub fn count_keys(&self) -> usize {
self.hash_container.get_hash_map().len()
}
}
fn main() {
let db = MyDB::new();
println!("key count: {}", db.count_keys());
}
答案 0 :(得分:2)
tl; dr:这是不可能的。
首先,这是无效的:
struct MyDB {
hash_container: HashMapContainer
}
HashMapContainer
是一个特征,但是您试图将其用作类型。相反,您将需要(1)引入受特征限制的类型参数:
struct MyDB<H: HashMapContainer> {
hash_container: H,
}
或者(2)使用特征对象,例如在Box
中:
struct MyDB {
hash_container: Box<dyn HashMapContainer>,
}
这些方法中的每一个都有不同的权衡。使用type参数会将类型固定为在编译时必须知道的类型。特质对象将更加灵活,因为具体类型可以在运行时更改,但会带来一些性能影响,以及对特质及其使用方式的一些限制。
由于要在运行时选择HashMapContainer
的实现,因此,根据字符串值,必须使用特征对象路由。但是,由于仅在运行时才知道具体类型,所以关联的类型也将仅在运行时才知道。这意味着编译器将无法对涉及相关类型的任何内容进行类型检查。
本质上是您的综合要求;动态更改特征实现并依赖特征的关联类型;不兼容。
如果您可以修复关联的类型,因此它始终是相同的,那么这可以工作:
struct MyDB {
hash_container: Box<dyn HashMapContainer<Value = SomeType>>,
}
或者,如果您希望将特征的实现限制为一组固定的已知类型,则可以将它们编码为枚举。
此处的实际答案将取决于您的实际需求以及可以在何处弯曲它们。