是否可以沿捕获的环境保存闭包以供以后调用?

Can I save a closure along the captured environment to call it later?

提问人:LucioleMaléfique 提问时间:7/18/2023 最后编辑:LucioleMaléfique 更新时间:7/18/2023 访问量:34

问:

我遇到过这种情况,我想创建一个结构,可以通过结构拥有的闭包进行修改。

我从来没有太深入地研究过闭合和捕捉环境,也没有深入研究过一生,但我想知道为什么借用检查器对我生气。这就是我所希望的:


struct A {
    pub a: usize,
    pub b: String,
    pub c: C,
}

struct C {
    pub modifier: Box<dyn FnMut()>
}

fn main() {
    let a = 3;
    let b = "Hello, World !".to_string();
    let c = C {
        modifier: Box::new(|| {
            a += 1;
            b.push('c');
        })
    };
    
    let mut my_struct = A {
        a, b, c
    };
    
    println!("a, b : {}, {}", my_struct.a, my_struct.b);
    (my_struct.c.modifier)();
    println!("a, b : {}, {}", my_struct.a, my_struct.b);
    
}

在这里,我在 C 结构体中的闭包确实捕获了我的变量 a 和 b,因此 a 和 b 的寿命必须比闭包长。但是,我将所有这些存储在同一个结构中,因此它们将同时被删除?这意味着如果 a 或 b 被丢弃,C 也会被丢弃?

这是一个游乐场链接

这不能编译,它抱怨 a 和 b 的 lng 生活不够。我们是这样的吗?

有没有一种已知的模式可以让人们实现这样的事情?(目标是闭包是用户定义的,并且可以修改它所在的结构。

防锈 瓶盖 寿命

评论

1赞 cafce25 7/18/2023
修改结构的闭包必须具有对结构的引用,因此它不能也存储在结构中。请参阅为什么不能在同一结构中存储值和对该值的引用?
0赞 cafce25 7/18/2023
此外,你关于某物何时停止存在的模型有点歪斜,一旦你把它移到 ,任何在这一点上停止有效的引用都会变得无效。毕竟,它不再位于同一内存位置。对于一个值实现,比如故事,有点不同,但对它的任何引用也不能离开函数。bmy_structbCopya
4赞 cafce25 7/18/2023
另一方面,用它存储闭包环境就像放在前面一样简单。move||
0赞 Chayim Friedman 7/18/2023
如果您不想使用 ,可以将它们作为参数传递给闭包。move

答:

0赞 cafce25 7/18/2023 #1

您可以添加一个方法,该方法使用正确的参数从 to 调用修饰符,这样您就不必存储对结构本身的引用:selfA

struct A {
    pub a: usize,
    pub b: String,
    pub c: C,
}

struct C {
    pub modifier: Box<dyn Fn(&mut usize, &mut String)>
}

impl A {
    fn call_modifier(&mut self) {
        (self.c.modifier)(&mut self.a, &mut self.b);
    }
}

fn main() {
    let a = 3;
    let b = "Hello, World !".to_string();
    let c = C {
        modifier: Box::new(|a, b| {
            *a += 1;
            b.push('c');
        })
    };
    
    let mut my_struct = A {
        a, b, c
    };
    
    println!("a, b : {}, {}", my_struct.a, my_struct.b);
    my_struct.call_modifier();
    println!("a, b : {}, {}", my_struct.a, my_struct.b);
    
}