Próbuję zaimplementować wyliczenie "polimorficzne" Input
, które ukrywa, czy czytamy z pliku lub ze standardowego wejścia. Dokładniej, próbuję zbudować wyliczenie, które będzie miało metodę lines
, która z kolei "przekaże" to wywołanie do File
zapakowanego w BufReader
lub do StdInLock
(oba z nich mają metodę lines()
).Jak zrobić polimorficzne IO (plik lub stdin) w Rust?
Oto wyliczenia:
enum Input<'a> {
Console(std::io::StdinLock<'a>),
File(std::io::BufReader<std::fs::File>)
}
Mam trzy metody:
from_arg
celu podjęcia decyzji, czy mamy do odczytu z pliku lub ze standardowego wejścia, sprawdzając, czy argument (filename) był pod warunkiem,file
owijania pliku zBufReader
,console
do locki Na stdin.
Realizacja:
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))
})
}
}
O ile mi zrozumieć, muszę wdrożyć BOT BufRead
i Read
cechy dla tej pracy. To moja próba:
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()
}
}
}
Wreszcie inwokacja:
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 */
}
}
Problem polega na tym, że kompilator I mówi mi, że jestem dopasowując wzór niewłaściwie i że mam mismatched types
. Próbowałem go zaspokoić:
match self {
Input::Console(std::io::StdinLock(ref c)) => c.lines(),
Input::File(std::io::BufReader(ref f)) => f.lines()
}
... ale to też nie działa.
W pierwszym przypadku Dostaję błąd mismatched types
:
poly_input.rs:43:40: 43:49 error: mismatched types:
expected `std::io::Lines<Input<'a>>`,
found `std::io::Lines<std::io::stdio::StdinLock<'_>>`
(expected enum `Input`,
found struct `std::io::stdio::StdinLock`) [E0308]
poly_input.rs:43 Input::Console(ref c) => c.lines(),
^~~~~~~~~
, a w drugim przypadku jest unresolved variant
błąd:
poly_input.rs:45:29: 45:47 error: unresolved enum variant, struct or const `StdinLock` [E0419]
poly_input.rs:45 Input::Console(std::io::StdinLock(ref c)) => c.lines(),
Jestem naprawdę z moim głębokość tutaj wydaje się.
Twoje obecne podejście nie zadziała, ponieważ 'StdinLock' zawiera odniesienie do obiektu' Stdin'. –
Czy mógłbyś rozwinąć trochę, jeśli masz czas? Dzięki. – neektza