我有一个CSV文件列表,我想在所有文件的行上生成一个迭代器。我因此使用flat_map()
:
extern crate csv;
extern crate rustc_serialize;
use std::path::Path;
use std::fs;
// simple struct used by the csv crate to deserialize the csv line into this Value
#[derive(RustcDecodable, RustcEncodable)]
pub struct Value {
pub id: String,
}
// I have an iterator over some csv files,
// I want an iterator of all the lines of all the files
fn do_stuff<I>(files: I)
where I: Iterator<Item = std::path::PathBuf>
{
let iter = files.flat_map(|f| {
let mut rdr = csv::Reader::from_file(f).unwrap().has_headers(false);
rdr.decode() // <- decode() takes rdr by ref
.map(|r| {
let b: Value = r.unwrap();
b.id //takes some values
})
});
// do stuff with iter
}
fn main() {
let paths: std::fs::ReadDir = fs::read_dir(".").unwrap();
do_stuff(paths.map(|p| p.unwrap().path()));
}
然而,借阅检查员对此并不满意:
error: `rdr` does not live long enough
rdr.decode().map(|r| {
^~~
note: reference must be valid for the block suffix following statement 0 at 22:7...
});
//do stuff with iter
}
note: ...but borrowed value is only valid for the block suffix following statement 0 at 16:76
let mut rdr = csv::Reader::from_file(f).unwrap().has_headers(false);
rdr.decode().map(|r| {
let b: Value = r.unwrap();
b.id
})
2使用的lambda(flat_map
中的那个和map
中的那个)不捕获其他变量,因此我不太明白为什么本地rdr
需要活得那么久。
decode
函数对rdr
进行了引用,因此似乎map
需要拥有引用rdr
...
答案 0 :(得分:3)
这有点挑剔,但对Rust的规则有意义。传递给public class CustomObject implements ICustomObject {
protected String name;
@AssistedInject
public CustomObject(@Assisted String name){
this.name = name;
}
}
的闭包是一个返回迭代器的函数,然后在flat_map
迭代器中排出。发生的事情是迭代器flat_map
依赖于对decode
的活动的引用,但rdr
在关闭结束时被删除了!
rdr
最简单的解决方法是:
|f| {
let mut rdr = csv::Reader::from_file(f).unwrap().has_headers(false);
rdr.decode() // <- decode() takes rdr by ref
.map(|r| {
let b: Value = r.unwrap();
b.id //takes some values
} // <--- Returns this iterator, which requires &'a mut rdr
} // <--- rdr dropped here
// <--- Uh oh, now we can't use the decoder, since rdr doesn't exist
返回一个向量,由 let v: Vec<_> = rdr.decode().map(...).collect();
v
迭代。它可能不是最高效的解决方案,但它很简单。
另一个解决方案是编写自己的flat_map
,按值struct
,并实现csv::Reader
,如下所示:
Iterator
然后你想做类似的事情:
fn next(&mut self) -> Option<WhateverType> {
self.rdr.decode().next().and_then(|v| {
v.unwrap().id
})
}