我正在尝试编写一个简单的计算器应用程序来掌握 FLTK,特别是 Rust 绑定。对于输出,我想在可以设置输出的地方存储一个字符串,这样处理起来更简单,但是,编译器确实不喜欢这样。
我正在尝试在循环中使用回调,因为我需要为所有按钮执行大约 9-10 次,并且我希望能够对需要一些标准回调的较大按钮数量重复它。
我已经尝试执行编译器的建议,让闭包通过
move
取得所有权,但问题是我无法将字符串取回以供以后使用,因为库使该函数无法拥有它除此之外,将所有权移交给无法将其交还的匿名函数是没有意义的。
我的编译器中当前代码的片段是
fn main() {
let mut number_buts: [Button; 10] = arr![Button::default(); 10];
let mut out_string: String = String::new();
for i in 1..number_buts.len()
{
let mut current_but = Button::default();
let call_back = |but: &mut Button| {
out_string.push_str(but.label().clone().as_str());
};
current_but.set_callback( call_back);
let _ = mem::replace(&mut number_buts[i], current_but);
}
}
我得到的错误是
error[E0373]: closure may outlive the current function, but it borrows `out_string`, which is owned by the current function
--> src\main.rs:46:25
|
46 | let call_back = |but: &mut Button| {
| ^^^^^^^^^^^^^^^^^^ may outlive borrowed value `out_string`
47 | out_string.push_str(but.label().clone().as_str());
| ---------- `out_string` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src\main.rs:50:9
|
50 | current_but.set_callback( call_back);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `out_string` (and any other referenced variables), use the `move` keyword
|
46 | let call_back = move |but: &mut Button| {
| ++++
error[E0499]: cannot borrow `out_string` as mutable more than once at a time
--> src\main.rs:46:25
|
46 | let call_back = |but: &mut Button| {
| ^^^^^^^^^^^^^^^^^^ `out_string` was mutably borrowed here in the previous iteration of the loop
47 | out_string.push_str(but.label().clone().as_str());
| ---------- borrows occur due to use of `out_string` in closure
...
50 | current_but.set_callback( call_back);
| ------------------------------------ argument requires that `out_string` is borrowed for `'static`
在 Rust 中,闭包通过三种方式捕获其环境:获取所有权、可变借用和不可变借用。当您希望闭包在不获取所有权的情况下修改某些内容时,您将面临 Rust 所有权和借用规则的挑战,特别是在像您这样的场景中,编译器需要确保跨潜在异步或基于回调的代码的内存安全。
考虑到您的要求和遇到的错误,一种解决方案是使用 Rc
以下是修改代码片段的方法:
use fltk::{prelude::*, *};
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let app = app::App::default();
let mut win = window::Window::default().with_size(400, 300);
let out_string = Rc::new(RefCell::new(String::new()));
let mut number_buts: Vec<button::Button> = Vec::new();
for i in 0..10 {
let out_str_clone = out_string.clone();
let mut btn = button::Button::new(40 * i, 0, 40, 40, &i.to_string());
btn.set_callback(move |_| {
out_str_clone.borrow_mut().push_str(&i.to_string());
println!("{}", out_str_clone.borrow());
});
number_buts.push(btn);
}
win.end();
win.show();
app.run().unwrap();
}
主要变更及说明:
这种方法非常适合 GUI 等单线程应用程序。但是,如果您在多线程上下文中工作,则 Rc