我对Rust很陌生。在尝试一些小事情时,我编写了以下代码。它仅扫描文件(作为参数)中的特定字符串(“ Started”),并打印出匹配的行:
use std::os;
use std::io::BufferedReader;
use std::io::File;
fn main() {
for target in os::args().iter() {
scan_file(target);
}
}
fn scan_file(path_str: &String) {
let path = Path::new(path_str.as_bytes());
let file = File::open(&path);
let mut reader = BufferedReader::new(file);
for line in reader.lines() {
match line {
Ok(s) => {
if s.as_slice().contains("Started ") {
print!("{}", s);
}
}
Err(_) => return,
}
}
}
我的问题是:如何重构函数scan_file
,使其看起来像这样(或足够类似)?:
fn scan_file(path_str: &String) {
for line in each_line_in_file_with_path(path_str) {
match line {
Ok(s) => {
if s.as_slice().contains("Started ") {
print!("{}", s);
}
}
Err(_) => return,
}
}
}
在此函数的新版本中,三个变量声明不见了。取而代之的是,该函数each_line_in_file_with_path
应该处理所有“将路径转换为行”,并返回迭代器。
我尝试了许多失败的尝试,总是由于变量超出我的需求超出范围的缘故。我了解我所遇到的问题(但我认为),但是在任何地方都找不到如何处理此问题的很好的解释。
无法实现工作each_line_in_file_with_path
功能-至少要在不增加一些开销和不安全代码的情况下才能实现。
让我们看一下所涉及的值及其类型。首先是path
类型Path
(posix::Path
或windows::Path
)的。这些类型的构造函数接收一个BytesContainer
按值,因此他们拥有它的所有权。这里没有问题。
接下来是file
类型。克隆它接收到的路径,因此这里再次没有问题。IoResult<File>
File::open()
接下来是reader
类型BufferedReader<IoResult<File>>
。就像一样Path
,的构造BufferedReader
函数按值接受参数并拥有所有权。
问题出在哪里reader.lines()
。此值为type Lines<'r, T: 'r>
。就像类型签名所暗示的那样,此结构包含一个借用的引用。的签名lines
显示了借方与借方之间的关系:
fn lines<'r>(&'r mut self) -> Lines<'r, Self>
我们each_line_in_file_with_path
现在如何定义?each_line_in_file_with_path
无法Lines
直接返回。您可能尝试过这样编写函数:
fn each_line_in_file_with_path<'a, T>(path: &T) -> Lines<'a, BufferedReader<IoResult<File>>>
where T: BytesContainer {
let path = Path::new(path);
let file = File::open(&path);
let reader = BufferedReader::new(file);
reader.lines()
}
这给出了编译错误:
main.rs:46:5: 46:11 error: `reader` does not live long enough
main.rs:46 reader.lines()
^~~~~~
main.rs:42:33: 47:2 note: reference must be valid for the lifetime 'a as defined on the block at 42:32...
main.rs:42 where T: BytesContainer {
main.rs:43 let path = Path::new(path);
main.rs:44 let file = File::open(&path);
main.rs:45 let reader = BufferedReader::new(file);
main.rs:46 reader.lines()
main.rs:47 }
main.rs:42:33: 47:2 note: ...but borrowed value is only valid for the block at 42:32
main.rs:42 where T: BytesContainer {
main.rs:43 let path = Path::new(path);
main.rs:44 let file = File::open(&path);
main.rs:45 let reader = BufferedReader::new(file);
main.rs:46 reader.lines()
main.rs:47 }
error: aborting due to previous error
那是因为我们试图返回一个a Lines
,该aBufferedReader
表示当函数返回时该a不再存在(该aLines
将包含一个悬空指针)。
现在,人们可能会想,“我将BufferedReader
随同一起返回Lines
”。
struct LinesInFileIterator<'a> {
reader: BufferedReader<IoResult<File>>,
lines: Lines<'a, BufferedReader<IoResult<File>>>
}
impl<'a> Iterator<IoResult<String>> for LinesInFileIterator<'a> {
fn next(&mut self) -> Option<IoResult<String>> {
self.lines.next()
}
}
fn each_line_in_file_with_path<'a, T>(path: &T) -> LinesInFileIterator<'a>
where T: BytesContainer {
let path = Path::new(path);
let file = File::open(&path);
let reader = BufferedReader::new(file);
LinesInFileIterator {
reader: reader,
lines: reader.lines()
}
}
这也不起作用:
main.rs:46:16: 46:22 error: `reader` does not live long enough
main.rs:46 lines: reader.lines()
^~~~~~
main.rs:40:33: 48:2 note: reference must be valid for the lifetime 'a as defined on the block at 40:32...
main.rs:40 where T: BytesContainer {
main.rs:41 let path = Path::new(path);
main.rs:42 let file = File::open(&path);
main.rs:43 let reader = BufferedReader::new(file);
main.rs:44 LinesInFileIterator {
main.rs:45 reader: reader,
...
main.rs:40:33: 48:2 note: ...but borrowed value is only valid for the block at 40:32
main.rs:40 where T: BytesContainer {
main.rs:41 let path = Path::new(path);
main.rs:42 let file = File::open(&path);
main.rs:43 let reader = BufferedReader::new(file);
main.rs:44 LinesInFileIterator {
main.rs:45 reader: reader,
...
main.rs:46:16: 46:22 error: use of moved value: `reader`
main.rs:46 lines: reader.lines()
^~~~~~
main.rs:45:17: 45:23 note: `reader` moved here because it has type `std::io::buffered::BufferedReader<core::result::Result<std::io::fs::File, std::io::IoError>>`, which is non-copyable
main.rs:45 reader: reader,
^~~~~~
error: aborting due to 2 previous errors
基本上,我们不能有一个包含借用引用的结构,该引用指向该结构的另一个成员,因为当该结构移动时,该引用将变为无效。
有2个解决方案:
创建一个BufferedReader
从文件路径返回a的函数,并.lines()
在for
循环中对其进行调用。
使一个函数接受一个接受每一行的闭包。
fn main() {
for target in os::args().iter() {
scan_file(target.as_slice());
}
}
fn for_each_line_in_file_with_path_do(path: &str, action: |IoResult<String>|) {
let path = Path::new(path.as_bytes());
let file = File::open(&path);
let mut reader = BufferedReader::new(file);
for line in reader.lines() {
action(line);
}
}
fn scan_file(path_str: &str) {
for_each_line_in_file_with_path_do(path_str, |line| {
match line {
Ok(s) => {
if s.as_slice().contains("Started ") {
print!("{}", s);
}
}
Err(_) => return,
}
});
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句