使用&Box <t>和&T作为参数的分解方法

时间:2019-03-01 17:06:57

标签: rust polymorphism traits trait-objects

我有一个需要使用trait参数调用的方法(我们叫它Listener)。原因是,有时我以前​​已将此特征参数存储到父结构中,因此它位于Box内,有时不存在。

所以我有两种方法:

  • fref<T>(t: &T) where T: Listener
  • fbox(t: &Box<dyn Listener>)

,我希望他们俩都致电f(t: ??)。现在,我在freffbox中复制了代码,它们虽然有效,但是效果不好。因此,我正在寻找f的签名,以使其可从freffbox进行调用以分解我的代码。我希望Box实现的特征之一等同于&(或至少在某个地方找到共同点)。

我尝试了以下操作:

  • f<T>(t: &T) where T: Listener,但随后无法从fbox打电话(Listener未实现Box<dyn Listener>)。
  • 然后将通话从fbox更改为f(&*t),以取消对Box<Listener>的装箱操作,但是由于t不是Size d,我无法

  • 正在写f<T>(t: &T) where T: std::borrow::Borrow<Listener>,但随后我无法从fref打电话(Borrow未实现Listener

  • AsRef<Listener>
  • 上次尝试使用Deref playground
trait Listener {}
struct Mouse {}
impl Listener for Mouse {}

fn fbox(t: &Box<Listener>) {
    f(t);
}

fn fref<T>(t: &T)
where
    T: Listener,
{
    f(t);
}

fn f<T>(_t: &T)
where
    T: std::ops::Deref<Target = Listener>,
{

}

fn create_listener() -> impl Listener {
    Mouse {}
}

fn main() {
    let mouse = create_listener();
    let box_mouse: Box<Listener> = Box::new(Mouse {});

    fref(&mouse);
    fbox(&box_mouse);
}

1 个答案:

答案 0 :(得分:4)

Listener是一个特征,所以Box<Listener>实际上是一个特征对象Box<dyn Listener>-不幸的是,dyn关键字当前是可选的。 Box<dyn Listener>&Mouse都实现Deref,并具有实现Target的关联Listener类型。对于&Mouse,解引用TargetMouse,但是对于Box<dyn Listener>,它是一个未知对象, unknown <的dyn Listener / em>大小。

要捕获所有这些信息,您可以像这样编写f

fn f<T, L>(_listener: &T)
where
    T: Deref<Target = L>,
    L: Listener + ?Sized
{
}

并从每个函数中调用它,如下所示:

fn fbox(listener: &Box<dyn Listener>) {
    f(listener);
}

fn fref<L>(listener: &L)
where
    L: Listener
{
    f(&listener);
}

另一种或许更简单的方法是放弃Deref约束,而只使用常规引用。使用Box::as_ref可以将Box变成参考,以便进行调用。对于特征对象而言,?Sized不受约束仍然有效,并且由于值始终位于指针后面,因此它仍然有效:

fn fbox(listener: &Box<dyn Listener>) {
    f(listener.as_ref());
}

fn fref<L>(listener: &L) where L: Listener {
    f(listener);
}

fn f<L>(_listener: &L)
where
    L: Listener + ?Sized
{
}