Я думаю, что вы на пути к использованию Option
в структуре Foo
.Предполагая, что структура становится следующей:
struct Foo {
file : Option<BufReader <File>>,
data : Vec <f64>,
}
Следующий код является возможным решением:
// Reads the file and strips the header
fn init_foo(fname : &str) -> Foo {
// Open the file
let mut file = BufReader::new(File::open(fname).unwrap());
// Dump the header
let mut header = String::new();
let _ = file.read_line(&mut header);
// Return our foo
Foo { file : Some(file), data : Vec::new() }
}
// Read the remaining foo data and process it
fn read_foo(foo : Foo) -> Option<Foo> {
let mut file = foo.file?;
// Strip one more line
let mut header_alt = String::new();
let _ = file.read_line(&mut header_alt);
// Read in the rest of the file line by line
let mut data = Vec::new();
for (lineno,line) in file.lines().enumerate() {
// Strip the error
let line = line.unwrap();
// Print some diagnostic information
println!("Line {}: val {}",lineno,line);
// Save the element
data.push(line.parse::<f64>().unwrap());
}
// Export foo
Some(Foo { data : data, file: None})
}
Обратите внимание, что в этом случае read_foo
возвращает необязательный Foo
из-за того факта, чтоfile
может быть None
.
На заметке, IMO, если вам не нужно, чтобы BufReader
был , путешествующим вместе с Foo
, я бы отказалсяЭто.Как вы уже обнаружили, вызов lines
вызывает движение, что затрудняет сохранение в другой структуре.В качестве предложения вы можете сделать поле file
просто String
, чтобы вы всегда могли извлечь BufReader
и прочитать файл при необходимости.
Например, вот решение, в котором имя файла(то есть a & str) можно превратить в Foo
со всей обработкой строки, выполненной непосредственно перед построением структуры.
// Buffered file IO
use std::io::{BufReader,BufRead};
use std::fs::File;
// Structure that contains a file
#[derive(Debug)]
struct Foo {
file : String,
data : Vec <f64>,
}
trait IntoFoo {
fn into_foo(self) -> Foo;
}
impl IntoFoo for &str {
fn into_foo(self) -> Foo {
// Open the file
let mut file = BufReader::new(File::open(self).unwrap());
// Dump the header
let mut header = String::new();
let _ = file.read_line(&mut header);
// Strip one more line
let mut header_alt = String::new();
let _ = file.read_line(&mut header_alt);
// Read in the rest of the file line by line
let mut data = Vec::new();
for (lineno,line) in file.lines().enumerate() {
// Strip the error
let line = line.unwrap();
// Print some diagnostic information
println!("Line {}: val {}",lineno,line);
// Save the element
data.push(line.parse::<f64>().unwrap());
}
Foo { file: self.to_string(), data }
}
}
fn main() {
// Read in our data from the file
let foo = "foo.txt".into_foo();
// Print out some debugging info
println!("{:?}",foo);
}
В этом случае нет необходимости беспокоиться о владении BufReader
, поскольку он создан, используется и отбрасывается в одной и той же функции.Конечно, я не полностью знаю ваш вариант использования, поэтому он может не подходить для вашей реализации.