我正在学习 Rust 并使用 Rust 和 Gtk 创建一个非常简单的应用程序:
extern crate gtk;
use gtk::prelude::*;
use gtk::{Window, WindowType, TextView, TextBuffer, timeout_add_seconds};
fn make_window() {
let window = Window::new(WindowType::Toplevel);
let textview = TextView::new();
window.add(&textview);
let buffer = match textview.get_buffer() {
Some(x) => x,
None => panic!("Textview did not contain a buffer."),
};
buffer.connect_changed(move |buffer: &TextBuffer| {
let b = buffer.clone(); // Why is this clone needed?
timeout_add_seconds(1, move || {
let ref buffer = b;
Continue(false)
});
});
window.show_all();
}
fn main() {
if gtk::init().is_err() {
println!("Failed to initialize GTK.");
return;
}
make_window();
gtk::main();
}
我很困惑为什么buffer.clone()
在内部关闭之前需要这样做。
如果我忽略它,我会收到关于生命周期的错误。但据我所知,无论有没有克隆,两者都有相同的生命周期。那么为什么一个有效而一个无效呢?
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:18:17
|
18 | let b = buffer; // Why is this clone needed?
| ^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 17:54...
--> src/main.rs:17:55
|
17 | buffer.connect_changed(move |buffer: &TextBuffer| {
| _______________________________________________________^ starting here...
18 | | let b = buffer; // Why is this clone needed?
19 | | timeout_add_seconds(1, move || {
20 | | let ref buffer = b;
21 | | Continue(false)
22 | | });
23 | | });
| |_____^ ...ending here
note: ...so that expression is assignable (expected >k::TextBuffer, found >k::TextBuffer)
--> src/main.rs:18:17
|
18 | let b = buffer; // Why is this clone needed?
| ^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:19:32: 22:10 b:>k::TextBuffer]` will meet its required lifetime bounds
--> src/main.rs:19:9
|
19 | timeout_add_seconds(1, move || {
| ^^^^^^^^^^^^^^^^^^^
但据我所知,无论有没有克隆,两者都有相同的生命周期。
这并不完全正确。如果你克隆一个变量,你现在有两个版本的变量。每个都可以由不同的所有者拥有,因此两者都可以有不同的生命周期。这正是你的情况发生的事情,它只是有点隐藏 - 感谢关闭魔法。
让我们再次查看您的代码(我更改了一些变量名称,以便稍后明确引用它们):
buffer_a.connect_changed(move |buffer_b: &TextBuffer| {
let b = buffer_b.clone(); // Why is this clone needed?
timeout_add_seconds(1, move || {
let ref buffer_c = b;
Continue(false)
});
});
在这里,变量b
是通过克隆创建的,并且首先存在于外部闭包中(它是那里的局部变量)。但随后它在作为闭包的内部闭包内使用move
。因此,b
被移动到所述内罩,然后拥有的TextBuffer
。是:内部闭包拥有缓冲区b
。这意味着它的b
生命周期与闭包一样长;独立于原来的一生!
为了确保我们理解所有内容,只需检查各种变量的类型:
buffer_a
: 类型 TextBuffer
buffer_b
: 类型&TextBuffer
(可能是从 借来的buffer_a
)b
:TextBuffer
再次输入(我们克隆了buffer_b
,带有 的clone()
签名clone(&T) -> T
)buffer_c
:&TextBuffer
再次(借用b
)这let ref buffer = b;
条线进一步迷惑了这一点。写起来更惯用let buffer = &b;
(两个版本都做同样的事情)。
如果我们不克隆,为什么 Rust 会抱怨?内部闭合需要(通过timeout_add_seconds()
)到是 'static
(更正式的:“满足'static
要求),这意味着关闭不能引用任何不长生不老(。 'static
),如果我们不这样做克隆,内罩会。buffer_a
不会永远存在的参考。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句