Tôi đang cố gắng triển khai một "đa hình" Input
enum để ẩn chúng ta đang đọc từ một tệp hay từ một stdin. Cụ thể hơn, tôi đang cố gắng xây dựng một enum sẽ có phương thức lines
sẽ lần lượt là "đại biểu" gọi tới số File
được bao bọc thành BufReader
hoặc đến StdInLock
(cả hai đều có phương thức lines()
).Làm thế nào để làm IO đa hình (File hoặc stdin) trong Rust?
Đây là enum:
enum Input<'a> {
Console(std::io::StdinLock<'a>),
File(std::io::BufReader<std::fs::File>)
}
tôi có ba phương pháp:
from_arg
cho việc quyết định xem chúng ta đang đọc từ một tập tin hoặc từ một thiết bị nhập chuẩn bằng cách kiểm tra xem liệu một cuộc tranh cãi (filename) là được cung cấp,file
để gói một tệp vớiBufReader
,console
cho locki ng stdin.
Việc thực hiện:
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))
})
}
}
Theo như tôi hiểu, tôi phải thực hiện bot BufRead
và Read
đặc điểm này để làm việc. Đây là nỗ lực của tôi:
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()
}
}
}
Cuối cùng, gọi:
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 */
}
}
Vấn đề là trình biên dịch tôi nói với tôi rằng tôi là mô hình kết hợp sai và rằng tôi có mismatched types
. Tôi đã cố thỏa mãn điều đó với:
match self {
Input::Console(std::io::StdinLock(ref c)) => c.lines(),
Input::File(std::io::BufReader(ref f)) => f.lines()
}
... nhưng điều đó cũng không có tác dụng.
Trong trường hợp đầu tiên tôi nhận được lỗi 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(),
^~~~~~~~~
, và trong trường hợp thứ hai một lỗi unresolved variant
:
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(),
Tôi thực sự ra khỏi sâu của tôi ở đây, dường như.
Cách tiếp cận hiện tại của bạn sẽ không hoạt động vì 'StdinLock' chứa tham chiếu đến đối tượng' Stdin'. –
Bạn có thể mở rộng một chút nếu bạn có thời gian không? Cảm ơn. – neektza