使用相关类型的特征的结构成员

时间:2019-01-17 10:30:16

标签: generics hashmap rust

我对此问题有一个后续问题:Expose a HashMap in a generic way that disregards the HashMap value

假设我要使用HashMapContainer(在上一个问题的第一个答案中定义的那个)作为另一个结构(让我们称之为MyDB)和MyDB中的成员构造函数我想决定将该成员构造为HashMapContainerImpl1还是HashMapContainerImpl2。我不想将MyDB定义为模板(例如MyDB<T>),因为MyDB用户并不关心HashMapMyDB的值构造函数将对此做出决定)。正确的实现方式是什么?

这是我想要实现的示例代码(它不会编译):

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());
}

1 个答案:

答案 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>>,
}

或者,如果您希望将特征的实现限制为一组固定的已知类型,则可以将它们编码为枚举。

此处的实际答案将取决于您的实际需求以及可以在何处弯曲它们。