该错误处理章锈书包含有关如何使用的组合子的例子Option和Result。读取文件并通过应用一系列组合器将内容解析为i32并以Result<i32, String>. 现在,当我查看代码时,我感到困惑。在那里,在一个 and_then 的闭包中,String创建了一个局部值,随后作为返回值传递给另一个组合器。
下面是代码示例:
use std::fs::File;
use std::io::Read;
use std::path::Path;
fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
File::open(file_path)
.map_err(|err| err.to_string())
.and_then(|mut file| {
let mut contents = String::new(); // local value
file.read_to_string(&mut contents)
.map_err(|err| err.to_string())
.map(|_| contents) // moved without 'move'
})
.and_then(|contents| {
contents.trim().parse::<i32>()
.map_err(|err| err.to_string())
})
.map(|n| 2 * n)
}
fn main() {
match file_double("foobar") {
Ok(n) => println!("{}", n),
Err(err) => println!("Error: {}", err),
}
}
Run Code Online (Sandbox Code Playgroud)
我所指的值是contents. 它被创建并随后在map应用于 的std::io::Result<usize>返回值的组合器中被引用Read::read_to_string。问题:我认为不标记闭包move会默认借用任何引用的值,这会导致借用检查器抱怨,它的contents寿命不够长。但是,这段代码编译得很好。这意味着,将String contents移入并随后移出闭包。为什么在没有明确的情况下这样做move?
我认为不使用 move 标记闭包会默认借用任何引用的值,
不完全的。编译器对闭包主体内的代码进行一些检查,并跟踪封闭变量的使用方式。
当编译器发现在变量上调用了一个方法时,它会查看接收者的类型(self, &self, &mut self)。当变量用作参数时,编译器还会跟踪它是按值、引用还是可变引用。无论最严格的要求是什么,都将是默认使用的要求。
有时,这种分析还不够完整——即使变量仅用作引用,我们也打算让闭包拥有该变量。这通常发生在返回闭包或将其交给另一个线程时。
在这种情况下,该变量是从闭包中返回的,这意味着它是按值使用的。因此变量将自动移动到闭包中。
偶尔的move关键字是太大,因为它移动的锤子的所有被引用的变量。有时你可能只想强制一个变量中移动而不是其他。在这种情况下,我所知道的最佳解决方案是进行显式引用并将引用移入:
fn main() {
let a = 1;
let b = 2;
{
let b = &b;
needs_to_own_a(move || a_function(a, b));
}
}
Run Code Online (Sandbox Code Playgroud)