以 &Box<T> 和 &T 作为参数的因式分解方法

Factorize methods taking &Box<T> and &T as argument

我有一个方法需要用特征参数调用(我们称之为 Listener)。原因是有时我之前将此特征参数存储到父结构中,因此它在 Box 中,有时不在

所以我有两种方法:

我希望他们都打电话给 f(t: ??)。现在我复制了 freffbox 中的代码,但效果不佳。所以我正在寻找 f 的签名,它可以从 freffbox 调用它来分解我的代码。我希望 Box 实现的特征之一等同于 &(或者至少在某处找到共同点)。

我尝试了以下方法:

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);
}

Listener 是一个特征,所以 Box<Listener> 真正的 一个特征对象,Box<dyn Listener> - 不幸的是 dyn 关键字目前是可选的。 Box<dyn Listener>&Mouse 都实现了 Deref,关联的 Target 类型实现了 Listener。在 &Mouse 的情况下,deref TargetMouse,但在 Box<dyn Listener> 的情况下,它是一个未知对象,dyn Listener of 未知 尺寸。

要捕获所有这些信息,您可以这样写 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_refBox 转换为引用以便调用它。 ?Sized un-constraint 对于 trait object case 仍然是必需的,并且仍然有效,因为值总是在指针后面:

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