【问题标题】:Question about generics and traits in Rust关于 Rust 中的泛型和特征的问题
【发布时间】:2019-05-05 17:46:23
【问题描述】:

我有 DoSomethingProvider 特征,它期望其函数之一的参数为特征类型 DoSomethingListener

我有一个具体的结构 DoSomethingManager,它有一个类型为 DoSomethingProvider 的成员,并将实现 DoSomethingListener 特征并将其作为侦听器传递给 DoSomethingProvider

希望代码能说明我正在尝试做的事情:

pub trait DoSomethingListener {
    fn something_was_done(msg: &str);
}

pub trait DoSomethingProvider<'a, T>
where
    T: DoSomethingListener,
{
    fn add_do_something_listener(listener: T);
}

/* note:  The struct below will implement DoSomethingListener, and has
 * a DoSomethingProvider field.  It will pass itself as a listener to
 * DoSomethingProvider (which listens to a message queue and notifies
 * listeners of certain events)
 */

//this doesn't work.  Compiler complains about unused type T
pub struct DoSomethingManager<'a, B, T>
where
    T: DoSomethingListener,
    B: DoSomethingProvider<'a, T>,
{
    provider: Box<B>,
    // doesn't have any member of type T
}

// ...

/* So I tried this:
 * this doesn't work.  Compiler complains that DoSomethingProvider
 * expects one type parameter
 */
pub struct DoSomethingManager<'a, B>
where
    B: DoSomethingProvider<'a>,
{
    provider: Box<B>,
    // doesn't have any member of type T
}

//...

/* this compiles, but its a hack */
pub struct DoSomethingManager<'a, B, T>
where
    T: DoSomethingListener,
    B: DoSomethingProvider<'a, T>,
{
    provider: Box<B>,
    dummy: Box<T>,
    // added unused dummy member of type T
}

我是一位经验丰富的 Python 开发人员,但我是 Rust 新手。在 Rust 中实现这种多态代码的正确方法是什么?

【问题讨论】:

    标签: generics rust traits


    【解决方案1】:

    DoSomethingProvider 更改为使用associated type 而不是侦听器类型的类型参数。

    pub trait DoSomethingListener {
        fn something_was_done(msg: &str);
    }
    
    pub trait DoSomethingProvider {
        type Listener: DoSomethingListener;
    
        fn add_do_something_listener(listener: Self::Listener);
    }
    
    pub struct DoSomethingManager<B>
    where
        B: DoSomethingProvider,
    {
        provider: Box<B>,
    }
    

    请注意,通过使用关联类型或类型参数,DoSomethingProvider 的特定实例将只能接受单个特定类型的侦听器。如果您希望能够注册各种类型的侦听器,则需要通过trait objects 使用动态调度。

    【讨论】:

    • 谢谢。特征对象提供了我所追求的行为。现在我必须考虑何时使用关联类型、类型参数或 trait 对象......
    【解决方案2】:

    我要编译的内容与解决此问题所需要做的事情相差不远,但我不喜欢这个解决方案。看来您确实必须添加一个使用 PhantomData 类型的虚拟字段。

    【讨论】:

      猜你喜欢
      • 2022-11-23
      • 2022-10-05
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 2020-12-24
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      相关资源
      最近更新 更多