我在将引用计数变量移动到需要实现的闭包中时遇到了一些问题FnMut。
下面的代码工作正常:
use std::rc::Rc;
fn main() {
let callback;
let data: Rc<Vec<f32>> = Rc::new(Vec::new());
{
let data = data.clone();
callback = move || {
data.iter().for_each(|v| println!("{}", v));
};
consumer(callback);
}
}
fn consumer<D>(callback: D)
where
D: FnMut(),
{
}
Run Code Online (Sandbox Code Playgroud)
如果我将闭包更改为:
callback = move || {
data;
};
Run Code Online (Sandbox Code Playgroud)
编译器产生错误:
use std::rc::Rc;
fn main() {
let callback;
let data: Rc<Vec<f32>> = Rc::new(Vec::new());
{
let data = data.clone();
callback = move || {
data.iter().for_each(|v| println!("{}", v));
};
consumer(callback);
}
}
fn consumer<D>(callback: D)
where
D: FnMut(),
{
}
Run Code Online (Sandbox Code Playgroud)
这个例子有效:
callback = move || {
let x = data[0];
println!("{}", x);
};
Run Code Online (Sandbox Code Playgroud)
这个例子没有:
callback = move || {
let x = data;
println!("{}", x[0]);
};
Run Code Online (Sandbox Code Playgroud)
使用let data: Arc<Mutex<Vec<f32>>> = Arc::new(Mutex::new(Vec::new()));,这有效:
callback = move || {
let x = data.lock().unwrap();
};
Run Code Online (Sandbox Code Playgroud)
这不会:
callback = move || {
let x = data;
};
Run Code Online (Sandbox Code Playgroud)
这背后的原因是什么?
\n\n下面的代码工作正常:
\nRun Code Online (Sandbox Code Playgroud)\nlet data: Rc<Vec<f32>> = Rc::new(Vec::new());\n{\n let data = data.clone();\n callback = move || {\n data.iter().for_each(|v| println!("{}", v));\n };\n
首先,当构造闭包时,data被移入其中,因为闭包被声明为move ||。这就是为什么如果你想data在闭包之外再次使用你需要事先克隆
然后,当调用闭包时, iter()是一个采用 的方法&self,因此data不会被方法调用移出;它是借来的,并且闭包仍然拥有它。因此,可以根据需要多次调用闭包 \xe2\x80\x94 它会自动实现Fn,而不仅仅是FnOnce.
\n\nRun Code Online (Sandbox Code Playgroud)\ncallback = move || {\n data;\n};\n
\n\nRun Code Online (Sandbox Code Playgroud)\ncallback = move || {\n let x = data;\n println!("{}", x[0]);\n};\n
在这里,当闭包被调用时,data被移动(通过值使用,而不是通过引用)。第一种情况,立即丢弃;在第二个中,它被移动到局部变量中x。
如果将一个值移出闭包,则该闭包仅实现FnOnce,并且只能被调用一次,因为如果第二次调用该闭包,则该值将不再可用。
一般来说,任何简单提及变量名都是一种举动。其他一切都是特定的例外:
\nCopy特征,那么它可以是副本而不是移动,这意味着原始值保持有效。(此处不适用,因为Rc未实现Copy。).iter()如果您调用诸如or之类的方法.lock(),则该方法可以采用&selfor &mut self;Rust 自动获取引用,就好像您已经编写过一样(&data).iter()一样。println!是一个宏,为了方便起见,它隐式引用其参数。如果你写&data;或let x = &data;,那么您将创建一个引用,该引用不会移动原始值。
| 归档时间: |
|
| 查看次数: |
4673 次 |
| 最近记录: |