generics - 作为使用关联类型的特征的结构成员
问题描述
我对这个问题有一个后续问题:Expose a HashMap in a generic way that disregards the HashMap value
假设我想使用HashMapContainer
(与上一个问题的第一个答案中定义的相同)作为另一个结构中的成员(我们称之为它MyDB
),并且在MyDB
构造函数中我想决定是否将此成员构造为HashMapContainerImpl1
or 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());
}
解决方案
tl;博士:这是不可能的。
首先,这是无效的:
struct MyDB {
hash_container: HashMapContainer
}
HashMapContainer
是一种特征,但您正试图将其用作一种类型。相反,您需要 (1) 引入受 trait 约束的类型参数:
struct MyDB<H: HashMapContainer> {
hash_container: H,
}
或者 (2) 使用 trait 对象,例如在 a 中Box
:
struct MyDB {
hash_container: Box<dyn HashMapContainer>,
}
这些方法中的每一种都有不同的权衡。使用 type 参数会将类型修复为在编译时必须知道的内容。trait 对象会更加灵活,因为具体类型可以在运行时更改,但具有一些性能影响以及对 trait 及其使用方式的一些限制。
由于您想HashMapContainer
在运行时根据字符串值选择实现,因此您必须使用 trait 对象路由。但是,由于具体类型仅在运行时已知,因此关联类型也仅在运行时已知。这意味着编译器将无法对涉及关联类型的任何内容进行类型检查。
本质上,您的综合要求;动态改变 trait 实现并依赖于 trait 的关联类型;不兼容。
如果您可以修复关联的类型,所以它总是相同的,那么这可以工作:
struct MyDB {
hash_container: Box<dyn HashMapContainer<Value = SomeType>>,
}
或者,如果您愿意将特征的实现限制为一组固定的已知类型,那么您可以将它们编码在一个枚举中。
这里的实际答案将取决于您的实际需求以及您可以在哪里弯曲它们。
推荐阅读
- tensorflow - 正确使用多输出/多标签模型的 tensorflow flow_from_dataframe
- javascript - D3.js 发送节点/图像的路径/链接
- javascript - Javascript 事件侦听器更改段落文本 onclick 按钮不起作用?
- c - 何时在 c 中使用 True not 或等等来代替 &&、||、!=、= 等运算符
- perl - (Windows 10) 尝试安装 PPM 和 CPAN 的 Perl 模块失败?
- swiftui - 如何在完成另一个功能后执行另一个功能
- vue.js - vue 点击二输入一键
- gradle - 在命令行中传递 gradle 任务参数
- python - 在 Seaborn 中绘制特定列值而不是每个列值
- gitlab - Gitlab CI:当某些用户完成提交时不触发管道