是否可以从另一个成员闭包调用成员闭包?

时间:2019-01-06 16:46:44

标签: rust

我正在使用盒装闭包在结构上使用回调。但是,我还不知道如何从另一个调用一个闭包:

struct MyStruct {
    first: Box<Fn()>,
    second: Box<Fn()>,
}

impl MyStruct {
    fn method(&mut self) {
        self.second = Box::new(|| {
            // How can I make this work?
            (self.first)();
        });
    }
}

fn main() {
    let _ = MyStruct {
        first: Box::new(|| {}),
        second: Box::new(|| {}),
    };
}

这给出了:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:8:32
   |
8  |           self.second = Box::new(|| {
   |  ________________________________^
9  | |             // How can I make this work?
10 | |             (self.first)();
11 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 7:5...
  --> src/main.rs:7:5
   |
7  | /     fn method(&mut self) {
8  | |         self.second = Box::new(|| {
9  | |             // How can I make this work?
10 | |             (self.first)();
11 | |         });
12 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &&mut MyStruct
              found &&mut MyStruct
   = note: but, the lifetime must be valid for the static lifetime...
   = note: ...so that the expression is assignable:
           expected std::boxed::Box<(dyn std::ops::Fn() + 'static)>
              found std::boxed::Box<dyn std::ops::Fn()>

在这种情况下,我不太确定这是什么意思。

我知道借用规则是导致错误的原因,但是Rust中是否有任何合法方法能够获得与我要执行的操作相同的效果?

我不确定仅凭此是否有意义,为什么我要这样做。这是最小的复制品。我可以提供一个更大的例子,但是涉及的更多。

1 个答案:

答案 0 :(得分:1)

这是您的问题的部分解决方案:请勿使用Box<Fn()>,而应使用Box<Fn(&MyStruct)>,即将“ self”显式传递给闭包。

但是,据我所知,这仅允许闭包采用&MyStruct(与&mut MyStruct相对),即闭包无法修改给定的MyStruct(这可能会或可能不足以满足您的用例。

struct MyStruct {
    first: Box<Fn(&MyStruct)>,
    second: Box<Fn(&MyStruct)>,
}

impl MyStruct {
    fn method(&mut self) {
        self.second = Box::new(|self2: &MyStruct| {
            (self2.first)(self2)
        });
    }
}

fn main() {
    let _ = MyStruct {
        first: Box::new(|_self_ignored| {}),
        second: Box::new(|_self_ignored| {}),    
    };
}

如果闭包应该修改MyStruct,则会遇到(self2.first)(self2)的问题,因为这将借用self2两次,一次是可变的。您可以通过暂时替换first / second来解决此问题,但是这样,每次调用first / second时都需要格外小心,因为它随时可能无法调用first / second

可能有unsafe种方法可以解决此问题。就是说,我想(或者至少希望如此)有一种更好的方法来实现您要实现的目标。