我有一个需要使用trait参数调用的方法(我们叫它Listener
)。原因是,有时我以前已将此特征参数存储到父结构中,因此它位于Box
内,有时不存在。
所以我有两种方法:
fref<T>(t: &T) where T: Listener
fbox(t: &Box<dyn Listener>)
,我希望他们俩都致电f(t: ??)
。现在,我在fref
和fbox
中复制了代码,它们虽然有效,但是效果不好。因此,我正在寻找f
的签名,以使其可从fref
和fbox
进行调用以分解我的代码。我希望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);
}
答案 0 :(得分:4)
Listener
是一个特征,所以Box<Listener>
实际上是一个特征对象Box<dyn Listener>
-不幸的是,dyn
关键字当前是可选的。 Box<dyn Listener>
和&Mouse
都实现Deref
,并具有实现Target
的关联Listener
类型。对于&Mouse
,解引用Target
为Mouse
,但是对于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
{
}