gpt4 book ai didi

rust - 为什么在闭包内克隆数据不能防止错误 "closure may outlive the current function"?

转载 作者:行者123 更新时间:2023-11-29 08:31:06 25 4
gpt4 key购买 nike

我用 gtk-rs 构建了一个 GTK 应用程序。当我构建主窗口时,我想使用一些动态参数,例如窗口高度。我创建了一个包含所有此类设置的结构,并希望将其用作构建 UI 的函数的输入参数:

fn main() {
let application =
gtk::Application::new(Some("id"), Default::default())
.expect("Initialization failed...");

let config = Config {width: 100., height: 100.};
application.connect_activate(|app| {
build_ui(app, config.clone());
});

// Use config further

application.run(&args().collect::<Vec<_>>());
}

#[derive(Debug, Clone)]
pub struct Config {
pub width: f64,
pub height: f64,
}

fn build_ui(application: &gtk::Application, config: Config) {
...
}

在调用 build_ui 时我不能使用对 config 的引用,因为这个函数可以在 main 函数完成后调用,因此 config 结构不再存在。

我的想法是创建一个配置结构的副本(它只是几个原始变量),它与原始变量分开存在,因此我不会遇到生命周期或所有权问题。

这是正确的方法吗?我究竟做错了什么?我得到了与借用配置结构相同的错误:

error[E0373]: closure may outlive the current function, but it borrows `config`, which is owned by the current function
--> src/main.rs:36:34
|
36 | application.connect_activate(|app| {
| ^^^^^ may outlive borrowed value `config`
37 | build_ui(app, config.clone());
| ------ `config` is borrowed here

最佳答案

一般说明

类似问题的最小再现:

fn move_and_print(s: String) {
println!("{}", s);
}

fn main() {
let s = String::from("Hello");

let print_cloned_s = || println!("{}", s.clone());

move_and_print(s);
print_cloned_s();
}

编译器提示:

error[E0505]: cannot move out of `s` because it is borrowed

我想克隆 s 以避免借用,从而允许以后使用它。那么,编译器怎么会说 s 是借来的呢?

前面的推理是完全正确的,但是,有一个微妙之处:Clone::clone 的签名是 clone(&self) -> Self。所以当clone被调用时,数据被clone函数借用!

解决方案是在创建闭包之前克隆数据,然后将其移动到闭包中:

fn move_and_print(s: String) {
println!("{}", s);
}

fn main() {
let s = String::from("Hello");

// I clone `s` BEFORE creating the closure:
let cloned_s = s.clone();

// Then I move the cloned data into the closure:
let print_cloned_s = move || println!("{}", cloned_s);

move_and_print(s);
print_cloned_s();
}

解决您的实际错误

正如我所说,您必须克隆配置并将此克隆移动到闭包中:

let cloned_config = config.clone();

application.connect_activate(move |app| {
build_ui(app, cloned_config.clone());
});

您还必须添加第二个克隆调用以允许闭包是 Fn 而不是 FnOnce。实际上,如果您将配置移动到 build_ui 中,该函数将无法使用两次。参见 this question获取更多信息。


如果我很好地理解您的需要,config 旨在成为必须共享的只读配置。在这种情况下,我根本不会移动它,例如将 build_ui 的签名更改为:

fn build_ui(application: &gtk::Application, config: &Config)

关于rust - 为什么在闭包内克隆数据不能防止错误 "closure may outlive the current function"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57659707/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com