代码之家  ›  专栏  ›  技术社区  ›  seladb

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

  •  0
  • seladb  · 技术社区  · 5 年前

    我有一个关于这个问题的后续问题: Expose a HashMap in a generic way that disregards the HashMap value

    如果我想用 HashMapContainer (与前一个问题的第一个答案中定义的相同)作为另一个结构中的成员(我们称之为 MyDB )在 专用数据 构造函数我要决定是否将此成员构造为 HashMapContainerImpl1 HashMapContainerImpl2 是的。我不想定义 专用数据 作为模板(例如 MyDB<T> )因为 专用数据 用户不关心 HashMap ( 专用数据 构造器将决定这一点)。正确的方法是什么?

    下面是我想要实现的目标的示例代码(它不编译):

    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 回复  |  直到 5 年前
        1
  •  2
  •   Peter Hall    5 年前

    这是不可能的。

    首先,这是无效的:

    struct MyDB {
        hash_container: HashMapContainer
    }
    

    HashMapContainer 是一种特质,但你想把它作为一种类型。相反,您需要(1)引入一个类型参数,该参数受特征约束:

    struct MyDB<H: HashMapContainer> {
        hash_container: H,
    }
    

    或者(2)使用trait对象,例如 Box 以下内容:

    struct MyDB {
        hash_container: Box<dyn HashMapContainer>,
    }
    

    每种方法都有不同的取舍。使用type参数可以将类型修复为编译时必须知道的类型。trait对象会更灵活,因为具体的类型可以在运行时更改,但会对性能产生一些影响,并对trait及其使用方式有一些限制。

    既然你想选择 哈希映射容器 在运行时,基于字符串值,您可以 不得不 遵循trait对象路径。但是,由于具体类型仅在运行时已知,因此关联的类型也将仅在运行时已知。这意味着编译器将无法类型检查任何涉及关联类型的内容。

    从本质上说,您的组合需求;动态地更改trait实现并依赖trait的关联类型;是不兼容的。

    如果可以修复关联的类型,使其始终相同,则此操作可以工作:

    struct MyDB {
        hash_container: Box<dyn HashMapContainer<Value = SomeType>>,
    }
    

    或者,如果您愿意将trait的实现限制为一组固定的已知类型,那么可以在枚举中对它们进行编码。

    这里的实际答案将取决于您的实际需求,以及您能够在哪里弯曲它们。