closures - 使用闭包创建回调系统

标签 closures rust

我正在尝试制作类似“回调系统”的东西。例如,其中有一个窗口和几个按钮。窗口为每个按钮设置回调。两个回调都应该改变窗口的状态。编译器不允许在我的闭包/回调中捕获 &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());

这里,为了修改btn,需要借用self作为mutable。您试图借用 self 作为闭包中的可变对象。这会立即遇到问题,因为 Rust 不允许您对同一对象有多个可变引用(称为别名)。这是该语言的内存安全保证的基本组成部分。

此外,从概念上讲,您正在尝试建立一个引用循环 - Window 知道 ButtonButton 知道 窗口。虽然这是可能的,但它通常不是您想要的。一旦引用有一个循环,就很难将它们分开。您还可以搜索其他询问有关在 Rust 中创建图形(而不是)的问题,以查看其他人遇到的类似问题。

理想情况下,您可以将代码结构化为一棵树。在这里,我选择了 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();
}

关于closures - 使用闭包创建回调系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29540167/

相关文章:

php - 推导 PHP 闭包参数

JavaScript:为什么仅当我将返回函数分配给变量时才会发生闭包?

ios - Swift/iOS SDK : Generic Function with Class Type/Name Closure/Block Issue

rust - 数组不能被 RangeFull 索引?

sql-server - 执行流程任务无法在作业中执行 Rust 脚本

javascript - JavaScript 函数中的参数值错误

javascript - 取消引用变量的闭包有用吗?

rust - 如何传递一个向量并返回一个字符串向量?

string - 以字符串形式访问 Vec<&[u8]> 的正确方法

module - 使用嵌套模块中的项目时为 "unresolved import"