Как хранить структуры (не экземпляры), которые реализуют общую черту? - PullRequest
0 голосов
/ 20 февраля 2020

Фон

У меня есть черта MyTrait:

trait MyTrait {
    fn name() -> String;

    fn foo();
}

name определяет его имя, а foo - его связанная функция , которая делает некоторую работу для меня.

Target

У меня есть много структур, которые реализуют эту черту, и я хочу определить функцию

fn do_work(name: &String);

, которая находит структуру TheStruct где TheStruct::name() равно name, и позвоните TheStruct::foo().

Задача

Чтобы достичь своей цели, мне нужно HashMap или использовать match, но целевое значение должна быть структура (не экземпляр) реализует MyTrait, но это кажется невозможным.

Обходной путь

Измените name() и foo() на методы структуры, то есть name(&self) и foo(&self), затем используйте HashMap или просто match, чтобы сделать все правильно. Но я думаю, что name() и foo() не нуждаются в особом экземпляре, зачем мне его создавать?

1 Ответ

1 голос
/ 20 февраля 2020

Если вы сопоставляете имя с действием, наиболее разумно было бы использовать HashMap<String, fn()> наиболее вероятно. Например:

use std::collections::{HashMap, hash_map::Entry};

trait MyTrait {
    fn name() -> String;

    fn foo();
}

struct Example;
impl MyTrait for Example {
    fn name() -> String { 
        "Example".to_string() 
    }
    fn foo() { 
        println!("Do Example"); 
    }
}

#[derive(Default)]
struct Worker {
    handlers: HashMap<String, fn()>,
}
impl Worker {
    fn new() -> Self {
        Default::default()
    }
    fn register_handler<T: MyTrait>(&mut self) {
        let name = T::name();
        match self.handlers.entry(name) {
            Entry::Occupied(_) => panic!("handler already registered"),
            entry => {entry.or_insert(T::foo);},
        }
    }
    fn do_work(&self, name: &str) {
        let handler = self.handlers.get(name).expect("unknown handler");
        handler();
    }
}

fn main() {
    let mut worker = Worker::new();
    worker.register_handler::<Example>();

    worker.do_work("Example");
}

( Playground Link )

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