首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将struct方法设置为回调

将struct方法设置为回调
EN

Stack Overflow用户
提问于 2017-04-05 08:15:04
回答 1查看 1.1K关注 0票数 3

我有一些结构,并希望这个结构的一个方法是回调。我尝试将回调设置为闭包,并调用其中的方法,但这不起作用。

这是我想要的例子。在本例中,我使用了草书库:

代码语言:javascript
复制
extern crate cursive;

use cursive::Cursive;
use cursive::views::{BoxView, SelectView, IdView};
use cursive::view::Selector;


struct SomeStruct {
    siv: Cursive,
}

impl SomeStruct {
    fn new(siv: Cursive) -> SomeStruct {
        let mut ss = SomeStruct {
            siv: siv
        };
        let mut select: SelectView<i32> = SelectView::new();
        select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
        ss.siv.add_fullscreen_layer(BoxView::with_full_screen(IdView::new("select", select)));
        ss
    }

    fn on_submit_callback(&mut self, siv: &mut Cursive, value: &i32) {
        println!("value - {}", value);
    }
}

fn main() {
    let siv = Cursive::new();
    let mut ss = SomeStruct::new(siv);
}

有编译器错误:

代码语言:javascript
复制
error[E0373]: closure may outlive the current function, but it borrows `ss`, which is owned by the current function
  --> src/main.rs:20:34
   |
20 |             select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
   |                                  ^^^^^^^^^^^^ -- `ss` is borrowed here
   |                                  |
   |                                  may outlive borrowed value `ss`
   |
help: to force the closure to take ownership of `ss` (and any other referenced variables), use the `move` keyword, as shown:
   |             select.set_on_submit(move |siv, value| ss.on_submit_callback(siv, value));

error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure
  --> src/main.rs:20:47
   |
20 |             select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
   |                                               ^^
   |
help: consider changing this closure to take self by mutable reference
  --> src/main.rs:20:34
   |
20 |             select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
EN

回答 1

Stack Overflow用户

发布于 2017-04-05 11:16:47

老实说,锈病不是很容易回收的.

在垃圾收集语言中,回调很容易,因为共享对象是一个问题,但在所有权显式的语言中则更难。在这种情况下,您有两种可能性:

  • 活动经理,
  • 以共有的方式耕耘。

后者对于小型应用程序来说很容易,但在更大的范围内可能会变得非常混乱(而且有漏洞)。尽管如此,我们还是从它开始吧。

Python最直接的翻译是使用共享所有权:引用计数指针Rc,包装一些CellRefCell (延迟检查以运行时)。

代码语言:javascript
复制
fn new(siv: Cursive) -> Rc<RefCell<SomeStruct>> {
    let mut ss = Rc::new(RefCell::new(SomeStruct {
        siv: siv
    }));

    let mut select: SelectView<i32> =
        Rc::new(RefCell::new(SelectView::new()));

    {
        let weak = ss.clone().downgrade();
        select.borrow_mut().set_on_submit(|siv, value|
            weak.upgrade()
                .map(|ss| ss.borrow_mut().on_submit_callback(siv, value))
        );
    }

    ss.borrow_mut().siv.add_fullscreen_layer(
        BoxView::with_full_screen(IdView::new("select", select))
    );

    ss
}

所以,让我们把我们的所有权故事说清楚:

  • ss拥有(部分) select
  • selectss的引用很弱。

弱引用对于打破循环是必要的,因为这将泄漏。

这一解决办法应该有效,但正如所提到的:

  • 在语法上有点笨重,
  • 跟踪使用Weak打破循环的位置有点复杂,
  • 如果你同时尝试从RefCell借款两次,其中一次借款是可变的,你将得到一个panic

简而言之:它很管用,但它不太好。

另一种解决方案是使用事件管理器。

事件循环是一个分离所有权的简单解决方案:与其在回调中直接调用on_submit_callback,不如将一个事件推送到事件管理器!

解决方案涉及更多的问题:

  • 你需要一些东西来拥有SomeStruct (可能还有其他),
  • ID系统(您传递一个ID而不是指针),
  • 可以通过ID检索组件以将事件分派给它的事件管理器,
  • ..。

另一方面,它工作得很好,并且一个解耦的系统可以更容易地与之交互。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43225547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档