我试图实现一个"多态"Input枚举,它隐藏了我们是从文件还是从stdin读取.更具体地说,我正在try 构建一个枚举,该枚举将有一个lines方法,该方法将把调用"委托"到BufReader中的FileStdInLock(两者都有lines()方法).

以下是枚举:

enum Input<'a> {
    Console(std::io::StdinLock<'a>),
    File(std::io::BufReader<std::fs::File>)
}

我有三种方法:

  • from_arg用于通过判断是否提供了参数(文件名)来确定我们是从文件还是从标准输入文件中读取,
  • BufReader包装一个文件,
  • console用于锁定标准DIN.

实施:

impl<'a> Input<'a> {
    fn console() -> Input<'a> {
        Input::Console(io::stdin().lock())
    }

    fn file(path: String) -> io::Result<Input<'a>> {
        match File::open(path) {
            Ok(file) => Ok(Input::File(std::io::BufReader::new(file))),
            Err(_) => panic!("kita"),
        }
    }

    fn from_arg(arg: Option<String>) -> io::Result<Input<'a>> {
        Ok(match arg {
            None => Input::console(),
            Some(path) => try!(Input::file(path)),
        })
    }
}

据我所知,我必须实现BufRead个和Read个特征,这样才能工作.这是我的try :

impl<'a> io::Read for Input<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Input::Console(ref mut c) => c.read(buf),
            Input::File(ref mut f) => f.read(buf),
        }
    }
}

impl<'a> io::BufRead for Input<'a> {
    fn lines(self) -> Lines<Self> {
        match self {
            Input::Console(ref c) => c.lines(),
            Input::File(ref f) => f.lines(),
        }
    }

    fn consume(&mut self, amt: usize) {
        match *self {
            Input::Console(ref mut c) => c.consume(amt),
            Input::File(ref mut f) => f.consume(amt),
        }
    }

    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        match *self {
            Input::Console(ref mut c) => c.fill_buf(),
            Input::File(ref mut f) => f.fill_buf(),
        }
    }
}

最后,调用:

fn load_input<'a>() -> io::Result<Input<'a>> {
    Ok(try!(Input::from_arg(env::args().skip(1).next())))
}

fn main() {
    let mut input = match load_input() {
        Ok(input) => input,
        Err(error) => panic!("Failed: {}", error),
    };

    for line in input.lines() { /* do stuff */ }
}

Complete example in the playground

编译器告诉我模式匹配错误,我有mismatched types个:

error[E0308]: match arms have incompatible types
  --> src/main.rs:41:9
   |
41 | /         match self {
42 | |             Input::Console(ref c) => c.lines(),
   | |                                      --------- match arm with an incompatible type
43 | |             Input::File(ref f) => f.lines(),
44 | |         }
   | |_________^ expected enum `Input`, found struct `std::io::StdinLock`
   |
   = note: expected type `std::io::Lines<Input<'a>>`
              found type `std::io::Lines<std::io::StdinLock<'_>>`

我试着满足于:

match self {
    Input::Console(std::io::StdinLock(ref c)) => c.lines(),
    Input::File(std::io::BufReader(ref f)) => f.lines(),
}

... 但这也不管用.

看来我真的有点不知所措.

推荐答案

这是最简单的解决方案,但将borrow 并锁定Stdin.

use std::fs::File;
use std::io::{self, BufRead, Read};

struct Input<'a> {
    source: Box<BufRead + 'a>,
}

impl<'a> Input<'a> {
    fn console(stdin: &'a io::Stdin) -> Input<'a> {
        Input {
            source: Box::new(stdin.lock()),
        }
    }

    fn file(path: &str) -> io::Result<Input<'a>> {
        File::open(path).map(|file| Input {
            source: Box::new(io::BufReader::new(file)),
        })
    }
}

impl<'a> Read for Input<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.source.read(buf)
    }
}

impl<'a> BufRead for Input<'a> {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.source.fill_buf()
    }

    fn consume(&mut self, amt: usize) {
        self.source.consume(amt);
    }
}

由于默认的trait方法,ReadBufReadInput中完全实现.所以你可以拨打Inputlines.

let input = Input::file("foo.txt").unwrap();
for line in input.lines() {
    println!("input line: {:?}", line);
}

Rust相关问答推荐

trait 中self 的显式生命周期似乎导致E0499无法在循环中多次borrow * emits 器作为可变的

为什么单元类型(空元组)实现了`Extend`trait?

如何从polars DataFrame中获取一个列作为Option String?<>

为什么我可以跟踪以前borrow 过的变量?房主在哪里?

如何实现泛型枚举的`Serde::Desialize`特性

创建Rust中元对象协议的动态对象 Select /重新分配机制

如何向下转换到MyStruct并访问Arc Mutex MyStruct实现的方法?

我如何制作一个变异迭代器来锁定内部数据直到删除?

为什么这个变量不需要是可变的?

为什么Deref类特征不构成?

Rust proc_macro 和 syn:解析空格

当我try 使用 SKI 演算中的S I I实现递归时,为什么 Rust 会失败?

如何将一个矩阵的列分配给另一个矩阵,纳尔代数?

Rust Axum 框架 - 解包安全吗?

std mpsc 发送者通道在闭包中使用时关闭

Rust并发读写引起的死锁问题

Rust/Serde/HTTP:序列化`Option`

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

Rust 生命周期:不能在方法内重新borrow 可变字段

如何阅读 HttpRequest 主体