【问题标题】:How to store structs (not instance) that implement a common trait?如何存储实现共同特征的结构(不是实例)?
【发布时间】:2020-02-20 02:53:30
【问题描述】:

背景

我有一个特质MyTrait

trait MyTrait {
    fn name() -> String;

    fn foo();
}

name 定义了它的名字,foo 是它的associated function,这对我有用。

目标

我有很多实现这个特性的结构,我想定义一个函数

fn do_work(name: &String);

找到结构体TheStruct,其中TheStruct::name()name,然后调用TheStruct::foo()

问题

为了实现我的目标,我需要一个HashMap 或使用match,但目标值应该是一个结构(而不​​是实例)实现MyTrait,但这似乎是不可能的。

解决方法

name()foo() 更改为结构方法,即name(&self)foo(&self),然后使用HashMap 或仅使用match 来解决问题。但我认为既然name()foo() 在设计上不需要实例,那我为什么需要实例化呢?

【问题讨论】:

  • 如果 hashmap 将类型名称映射到函数,您能否将其设为 HashMap<String, fn()>,因此将项目插入映射以查找函数的功能是该函数的责任,所以do_work 根本不需要知道MyTrait
  • @loganfsmyth 这行得通。谢谢!
  • 酷,我会添加一个答案。

标签: rust


【解决方案1】:

如果您要将名称映射到操作,则最有可能使用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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 2021-05-18
    相关资源
    最近更新 更多