我试图在特征对象上使用回调函数。我将问题简化为以下代码(playpen):
trait Caller {
fn call(&self, call: fn(&Caller)) where Self: Sized {
call(self)
}
}
struct Type;
impl Caller for Type {}
fn callme(_: &Caller) {}
fn main() {
let caller: Box<Caller> = Box::new(Type);
caller.call(callme); // does not work
//callme(&*caller); // works
}
导致
<anon>:14:12: 14:24 error: the trait `core::marker::Sized` is not implemented for the type `Caller` [E0277]
<anon>:14 caller.call(callme); // does not work
^~~~~~~~~~~~
添加Sized
绑定会Caller
导致:
<anon>:3:14: 3:18 error: cannot convert to a trait object because trait `Caller` is not object-safe [E0038]
我真的不明白为什么我需要Sized
特质。有趣的是,如果我直接使用回调,它会起作用。我该如何工作?
编辑:感谢的答案,我现在想出了一个不错的解决方案
trait Caller {
fn borrow(&self) -> &Caller;
fn call(&self, call: fn(&Caller)) {
call(self.borrow())
}
}
struct Type;
impl Caller for Type {
fn borrow(&self) -> &Caller { self }
}
fn callme(_: &Caller) {}
fn main() {
let caller: Box<Caller> = Box::new(Type);
caller.call(callme);
}
的参数call
中fn call
需要的性状对象&Caller
,因此调用它需要强迫的self
(类型的参考&Self
),以一个&Caller
性状对象。只有在&Self
使用细指针而非特质对象或&[T]
切片之类的粗指针时,强制才可能执行。&Self
确切地说是什么时候是细指针Self: Sized
。编译器默认将Self
in trait设为not Sized
,因此需要额外的限制。该Sized
特征代表该类型有一个在编译时已知的大小,没有必要存储额外的信息(指针旁边,使其成为“胖”)来计算它在运行时。
不幸的是,这留下了一个漏洞:AFAIK,实际上不可能将这种方法作为默认方法,并且仍然无法在特征对象上调用它,因为特征对象&Caller
具有Self = Caller
not方法Sized
。但是,如果为每种类型手动实现该方法,则应该可以使用:
trait Caller {
fn call(&self, call: fn(&Caller));
}
struct Type;
impl Caller for Type {
fn call(&self, call: fn(&Caller)) {
call(self)
}
}
fn callme(_: &Caller) {}
fn main() {
let caller: Box<Caller> = Box::new(Type);
caller.call(callme);
}
call
特质中的方法声明不再需要,where Self: Sized
因为它不尝试执行特质对象强制本身,并且具体实现对如何获得&Caller
特质对象具有更多控制。对于Sized
类型,它可以直接工作,就像原始where Self: Sized
代码一样。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句