问题描述
我将一些Python移植到Rust作为学习练习,需要从文件或标准输入中获取输入。我在一个结构中保留了输入的句柄,所以我想我只是制作一个 Box< io :: Read>
但是我遇到了需要寻找的情况在输入上, seek
不是 Read
特征的一部分。我知道你不能在管道中寻找,所以我要继续并且现在假设这个方法只在输入是一个文件时才被调用,但是我的问题是我无法在Rust中检查它并且向下转发。 / p>
我知道我可以为两种输入类型使用枚举,但似乎应该有更优雅的方式来执行此操作。这就是我的问题,你是如何做到这一点而不是弄得一团糟?
是否可以将stdin或文件包装在同一种缓冲区中以便我可以使用那种类型而不用担心IO的类型?
我知道,你说你想要一些更优雅而没有枚举的东西,但我认为enum-solution 非常优雅。所以这是一次尝试:
使用std :: fs;
使用std :: io :: {self,Read,Seek,SeekFrom};
enum输入{
文件(fs ::文件),
Stdin(io :: Stdin),
}
impl读取输入{
fn read(& mut self,buf:& mut [u8]) - > IO ::结果< USIZE> {
match * self {
Input :: File(ref mut file)=> file.read(buf),
输入:: Stdin(ref mut stdin)=> stdin.read(buf),
}
}
}
impl寻求输入{
fn seek(& mut self,pos:SeekFrom ) - > IO ::结果< U64> {
match * self {
Input :: File(ref mut file)=> file.seek(pos),
输入:: Stdin(_)=> {
Err(io :: Error :: new(
io :: ErrorKind :: Other,
stdin-input不支持,
))
},
}
}
}
放置这样的代码在你的一些子模块中,不再担心它太多了。您可以使用输入
类型的对象,就像使用文件
一样:您必须处理搜索错误,所以处理无法通过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(我应该处理那个......))
};
let mut v = Vec :: new();
让_idc = input.read_to_end(& mut v);
匹配input.seek(SeekFrom :: End(0)){
Err(_)=> println!(哦noes :(),
Ok(字节)=> println!(是的,输入是{}长,字节),
}
I am porting some Python to Rust as a learning exercise and need to take input from either a file or stdin. I keep a handle to my input in a struct so I thought I'd just make a Box<io::Read>
but I ran into a situation where I need to seek on the input, and seek
isn't part of the Read
trait. I know you can't seek in pipes, so I'm going ahead and assuming for now that this method only gets called when the input is a file, but my problem is that I can't check that and downcast in Rust.
I know that I could use an enum for the two input types, but it seems like there should be a more elegant way to do this. And that's my question, how do you do this and not make a mess?
Is it possible to wrap stdin or a file in the same sort of buffer so I could just use that type and not worry about the type of IO?
I know, you said you wanted something more elegant and without enums, but I think the enum-solution is fairly elegant. So here is one attempt:
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",
))
},
}
}
}
Put code like that in some sub module of yours and don't worry about it too much anymore. You can use an object of type Input
just like you would use a File
: you have to handle seek errors anyway, so handling the inability to seek by stdin should be super easy. An example:
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),
}
这篇关于如果我不能搜索stdin,我如何从stdin或文件中获取输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!