Io 如何管理Rust中结构中保存的文件的所有权?

Io 如何管理Rust中结构中保存的文件的所有权?,io,rust,Io,Rust,有没有一种好方法可以使用Rust处理结构中保存的文件的所有权?作为一个简单的示例,请考虑: // Buffered file IO use std::io::{BufReader,BufRead}; use std::fs::File; // Structure that contains a file #[derive(Debug)] struct Foo { file : BufReader <File>,

有没有一种好方法可以使用Rust处理结构中保存的文件的所有权?作为一个简单的示例,请考虑:

// Buffered file IO
use std::io::{BufReader,BufRead};
use std::fs::File;            

// Structure that contains a file
#[derive(Debug)]
struct Foo {                
    file : 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 : file, data : Vec::new() }          
}   

// Read the remaining foo data and process it
fn read_foo(mut foo : Foo) -> Foo {

    // Strip one more line
    let mut header_alt = String::new();
    let _ = foo.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 foo.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
    Foo { data : data, ..foo}
}   

fn main() {

    // Initialize our foo
    let foo = init_foo("foo.txt");

    // Read in our data
    let foo = read_foo(foo); 

    // Print out some debugging info
    println!("{:?}",foo); 
} 
//缓冲文件IO
使用std::io::{BufReader,BufRead};
使用std::fs::File;
//包含文件的结构
#[导出(调试)]
结构Foo{
档案:BufReader,
资料来源:Vec,
}   
//读取文件并剥离标题
fn init_foo(fname:&str)->foo{
//打开文件
让mut file=BufReader::new(file::open(fname).unwrap());
//卸下收割台
让mut header=String::new();
let=file.read\u行(&mut头);
//归还我们的食物
Foo{file:file,data:Vec::new()}
}   
//读取剩余的foo数据并对其进行处理
fn read_foo(mut foo:foo)->foo{
//再剥一条线
让mut header_alt=String::new();
let=foo.file.read\u行(&mut header\u alt);
//逐行读入文件的其余部分
让mut data=Vec::new();
for foo.file.lines().enumerate()中的(lineno,line){
//消除错误
让line=line.unwrap();
//打印一些诊断信息
println!(“行{}:val{}”,行号,行);
//保存元素
data.push(line.parse::().unwrap());
}   
//出口食品
Foo{data:data,…Foo}
}   
fn main(){
//初始化我们的foo
设foo=init_foo(“foo.txt”);
//读入我们的数据
设foo=read_foo(foo);
//打印出一些调试信息
println!(“{:?}”,foo);
} 
这将导致编译错误:

error[E0382]: use of moved value: `foo.file`
  --> src/main.rs:48:5
   |
35 |     for (lineno,line) in foo.file.lines().enumerate() {
   |                          -------- value moved here
...
48 |     Foo { data : data, ..foo}
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move
   |
   = note: move occurs because `foo.file` has type `std::io::BufReader<std::fs::File>`, which does not implement the `Copy` trait

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
error: Could not compile `rust_file_struct`.

To learn more, run the command again with --verbose.
错误[E0382]:使用移动值:`foo.file`
-->src/main.rs:48:5
|
35 | for foo.file.lines().enumerate()中的(lineno,line){
|-----此处移动的值
...
48 | Foo{数据:数据,…Foo}
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^移动后此处使用的值
|
=注意:发生移动是因为`foo.file`的类型为`std::io::BufReader`,而该类型不实现`Copy`特性
错误:由于上一个错误而中止
有关此错误的详细信息,请尝试“rustc--explain E0382”。
错误:无法编译'rust\u file\u struct'。
要了解更多信息,请使用--verbose再次运行该命令。
当然,这是有道理的拥有缓冲文件的所有权,因此我们不能在返回中使用值。让我困惑的是处理这种情况的更好方法。当然,在for循环之后,文件被消耗了,所以它确实无法使用。为了更好地表示这一点,我们可以将文件表示为
选项
。然而,这会导致一些悲伤,因为第二个
read\u line
调用,在
read\u foo
的内部,需要一个对
文件的可变引用,我不知道如何获得它,它被包装在
选项中。有没有处理所有权的好方法


要明确的是,这是一个精简的示例。在实际用例中,有几个文件和其他数据。我以这种方式构造东西,因为它表示来自命令行选项的配置。有些选项是文件,有些是标志。在任何一种情况下,我都希望对这些选项进行一些处理,但不是全部处理尽早删除文件以抛出适当的错误。

我认为在
Foo
struct中使用
选项
是正确的。假设struct变为:

struct Foo {                
    file : Option<BufReader <File>>,
    data : Vec <f64>,   
}
在这种情况下,不必担心
BufReader
的所有权,因为它是在同一个函数中创建、使用和丢弃的。当然,我不完全了解您的用例,因此这可能不适合您的实现

// 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})
} 
// 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); 
}