Структурируйте членов, которые являются чертами, которые используют связанные типы - PullRequest
0 голосов
/ 17 января 2019

У меня есть дополнительный вопрос к этому вопросу: Представьте HashMap общим способом, который игнорирует значение HashMap

Предположим, я хочу использовать 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());
}

1 Ответ

0 голосов
/ 17 января 2019

tl; др: это невозможно.

Прежде всего, это недействительно:

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

В качестве альтернативы, если вы хотите ограничить реализации черты фиксированным набором известных типов, вы можете закодировать их в перечислении.

Фактический ответ здесь будет зависеть от ваших реальных требований и от того, где вы сможете согнуть их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...