我在试着制作一个类似"回调系统"的东西.例如,有一个窗口和几个按钮.该窗口 for each 按钮设置回调.两个回调都应该更改窗口的状态.编译器不允许在我的闭包/回调中捕获&self个,我不知道如何使其工作.

我应该遵循哪些常见的回调模式?

这是一个简单的例子,因为所有组件都有相同的生命周期 .如果组件的使用生命周期 不同呢?

struct Button<'a> {
    f: Option<Box<Fn() + 'a>>,
}

impl<'a> Button<'a> {
    fn new() -> Button<'a> { Button { f: None } }
    fn set<T: Fn() + 'a>(&mut self, f: T) { self.f = Some(Box::new(f)); }
    fn unset(&mut self) { self.f = None; }
    fn call(&self) { match self.f { Some(ref f) => f(), None => () } }
}

struct Window<'a> {
    btn: Button<'a>,
    //btns: Vec<Button<'a>>,
}

impl<'a> Window<'a> {
    fn new() -> Window<'a> {
        Window { btn: Button::new() }
    }

    fn hi(&mut self) { // self is mutable
        println!("callback");
    }

    fn run(&mut self) {
        // Compile error: cannot infer an appropriate lifetime for
        // capture of `self` by closure due to conflicting requirements
        self.btn.set(|| self.hi()); // How to make it work?
        self.btn.call();
        self.btn.unset();
    }
}

fn main() {
    let mut wnd = Window::new();
    wnd.run();
}

推荐答案

这条线会给你带来直接的问题:

self.btn.set(|| self.hi());

在这里,您需要borrow self作为可变项,以便修改btn.你正在试图借self英镑,因为这笔钱在交割时是可变的.这将立即遇到问题,因为Rust不允许对同一对象(称为aliasing)有多个可变引用.这是语言记忆安全保障的一个基本部分.

此外,从概念上讲,你试图建立一个参考循环——Window人知道Button人,Button人知道Window人.虽然这是可能的,但往往不是你想要的.一旦参考文献有了一个循环,就很难理清它们.你也可以搜索其他关于在 rust 迹中创建graphs(而不是trees)的问题,看看其他人有过类似的问题.

理想情况下,您可以将代码构造为一棵树.在这里,我 Select 了Button人可以知道Window人,但不是相反:

struct Button<'a> {
    f: Option<Box<FnMut() + 'a>>,
}

impl<'a> Button<'a> {
    fn new() -> Button<'a> { Button { f: None } }
    fn set<T: FnMut() + 'a>(&mut self, f: T) { self.f = Some(Box::new(f)); }
    fn unset(&mut self) { self.f = None; }
    fn call(&mut self) { match self.f { Some(ref mut f) => f(), None => () } }
}

struct Window;

impl Window {
    fn hi(&mut self) {
        println!("callback");
    }
}

fn main() {
    let mut wnd = Window;
    let mut btn = Button::new();
    btn.set(|| wnd.hi());
    btn.call();
    btn.unset();
}

Rust相关问答推荐

程序退出后只写入指定管道的数据

创建包含缺失值的框架

亚性状上位性状上的 rust 病伴生型界限

如何实现泛型枚举的`Serde::Desialize`特性

如何导入crate-type=[";cdylib;]库?

重写Rust中的方法以使用`&;mut self`而不是`mut self`

当发送方分配给静态时,Tokio MPSC关闭通道

rust中的库插件管理器,现在是否可行?

为什么rustc会自动降级其版本?

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

借来的价值生命周期 不够长,不确定为什么它仍然是借来的

Rust 中的生命周期:borrow 的 mut 数据

使用 lalrpop 在 rust 中解析由 " 引用的字符串

如果不满足条件,如何在 Rust 中引发错误

打印 `format_args!` 时borrow 时临时值丢失

使用方法、关联函数和自由函数在 Rust 中初始化函数指针之间的区别

在 Rust 中返回对枚举变体的引用是个好主意吗?

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?

如何迭代调用可能会失败的函数?操作员?

当引用不再被borrow 时,Rust 不会得到它