Rust Book的Error Handling chapter包含有关如何使用Option
和Result
的组合器的示例。读取文件并通过应用一系列组合器将内容解析为i32
并在Result<i32, String>
中返回。
现在,当我查看代码时,我感到困惑。在那里,在an_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),
}
}
我指的是contents
。它是在应用于map
std::io::Result<usize>
返回值的Read::read_to_string
组合器中创建并稍后引用的。
问题:我认为用move
标记闭包的不会默认借用任何引用的值,这会导致借用检查器抱怨,contents
不会长寿足够。但是,这段代码编译得很好。这意味着,String
contents
被移入闭包中,并且随后被移出。为什么没有明确的move
?
答案 0 :(得分:3)
我认为不标记带移动的闭包会默认借用任何引用的值,
不完全。编译器对闭包体内的代码进行了一些检查,并跟踪闭合变量的使用方式。
当编译器发现在变量上调用方法时,它会查看接收器的类型(self
,&self
,{{1} })。当变量用作参数时,编译器还会通过值,引用或可变引用来跟踪它。无论最严格的要求是什么,默认情况下都会使用。
偶尔,这种分析还不够完整 - 即使变量仅用作参考,我们打算让闭包拥有变量。这通常发生在返回闭包或将其移交给另一个线程时。
在这种情况下,变量从闭包返回,这必然意味着它被值使用。因此变量将自动移入闭包中。
偶尔 &mut self
关键字太大了,因为它会移动所有引用的变量。有时您可能只想强制一个变量被移入而不是其他人。在这种情况下,我所知道的最佳解决方案是制作一个明确的引用并移动引用:
move