我正在将一些Python移植到Rust作为学习练习,并且需要从文件或标准输入中获取输入。我将输入句柄保留在一个结构中,所以我以为自己会做一个Box<io::Read>
输入,但是遇到了需要寻找输入项而seek
不是Read
特征的一部分的情况。我知道您无法在管道中搜索,因此我现在继续假设该方法仅在输入是文件时才被调用,但是我的问题是我无法在Rust中对其进行检查和下调。
我知道我可以为两种输入类型使用一个枚举,但是似乎应该有一种更优雅的方式来做到这一点。这就是我的问题,您如何做到这一点而又不会一团糟?
是否可以将stdin或文件包装在相同类型的缓冲区中,以便我可以仅使用该类型,而不必担心IO的类型?
我知道,你说你想要的东西更优雅和不枚举,但我认为枚举的解决方案是相当优雅。因此,这是一种尝试:
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",
))
},
}
}
}
将这样的代码放在您的某个子模块中,不必再担心太多了。您可以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),
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句