gpt4 book ai didi

rust - 在特征对象上使用回调

转载 作者:行者123 更新时间:2023-11-29 07:51:28 24 4
gpt4 key购买 nike

我正在尝试对特征对象使用回调函数。我将我的问题简化为以下代码 ( 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
^~~~~~~~~~~~

添加绑定(bind)到 CallerSized 导致:

<anon>:3:14: 3:18 error: cannot convert to a trait object because trait `Caller` is not object-safe [E0038]

我真的不明白为什么我需要在特征上绑定(bind)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);
}

最佳答案

fn call 中的参数call 接受一个特征对象&Caller,所以调用它需要强制self&Caller 特征对象的引用(&Self 类型)。只有当 &Self 是一个瘦指针而不是像特征对象或 &[T] 切片这样的胖指针时,强制转换才有可能。 &Self 恰好是 Self: Sized 时的瘦指针。编译器在没有 Sized 的特征中默认为 Self,因此需要额外的限制。 Sized trait表示该类型具有在编译时已知的大小,因此无需存储额外信息(在指针旁边,使其“胖”)以在运行时计算它。

不幸的是,这留下了一个漏洞:AFAIK,实际上不可能让这样的方法成为默认方法并且仍然能够在特征对象上调用它,因为特征对象 &CallerSelf = Caller 不是 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);
}

trait 中的 call 方法声明不再需要 where Self: Sized,因为它本身并不试图进行 trait 对象强制转换,具体实现对如何获取 &Caller 特征对象有更多的控制。对于 Sized 类型,它直接工作,就像原始的 where Self: Sized 代码一样。

关于rust - 在特征对象上使用回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28940727/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com