如果我不能搜索stdin,我如何从stdin或文件中获取输入?

Cam*_*rzt 6 io traits downcast rust

我正在将一些Python移植到Rust作为学习练习,需要从文件或标准输入中获取输入.我保留了一个结构中输入的句柄,所以我想我只是做了一个Box<io::Read>但是我遇到了一个需要寻求输入的情况,而seek不是Read特征的一部分.我知道你不能在管道中寻找,所以我要继续并且现在假设这个方法只在输入是一个文件时才被调用,但我的问题是我无法在Rust中检查它和downcast.

我知道我可以使用enum作为两种输入类型,但似乎应该有一种更优雅的方式来做到这一点.这就是我的问题,你是如何做到这一点而不是弄得一团糟?

是否可以将stdin或文件包装在同一种缓冲区中,以便我可以使用该类型而不用担心IO的类型?

Luk*_*odt 5

我知道,你说你想要的东西更优雅和不枚举,但我认为枚举的解决方案相当优雅.所以这是一次尝试:

use std::fs;
use std::io::{self, Read, Seek, SeekFrom};

enum Input {
    File(fs::File),
    Stdin(io::Stdin),
}

impl Read for Input {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Input::File(ref mut file) => file.read(buf),
            Input::Stdin(ref mut stdin) => stdin.read(buf),
        }
    }
}

impl Seek for Input {
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
        match *self {
            Input::File(ref mut file) => file.seek(pos),
            Input::Stdin(_) => {
                Err(io::Error::new(
                    io::ErrorKind::Other, 
                    "not supported by stdin-input",
                ))
            },
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

把这样的代码放在你的某个子模块中,不要再担心它太多了.你可以Input像使用a一样使用类型的对象File:无论如何你必须处理搜索错误,所以处理无法通过stdin搜索应该是非常容易的.一个例子:

let arg = std::env::args().nth(1).unwrap();
let mut input = if arg == "--" {
    Input::Stdin(io::stdin())
} else {
    Input::File(fs::File::open(&arg).expect("I should handle that.."))
};

let mut v = Vec::new();
let _idc = input.read_to_end(&mut v);

match input.seek(SeekFrom::End(0)) {
    Err(_) => println!("oh noes :("),
    Ok(bytes) => println!("yeah, input is {} long", bytes),
}
Run Code Online (Sandbox Code Playgroud)