[英]Rust generic local variable
從《Rust in Action》(Manning,目前是 MEAP)一書中,第 2 章的最后一個例子展示了一種實現通用函數的方法,該函數可以處理BufRead + Sized
參數:
fn process_lines<T: BufRead + Sized>(reader: T, re: Regex) {
for line_ in reader.lines() {
let line = line_.unwrap();
match re.find(&line) {
Some(_) => println!("{}", line),
None => (),
}
}
}
使用它的代碼如下所示:
let input = args.value_of("input").unwrap_or("-");
if input == "-" {
let stdin = io::stdin();
let reader = stdin.lock();
process_lines(reader, re);
} else {
let f = File::open(input).unwrap();
let reader = BufReader::new(f);
process_lines(reader, re);
}
我想知道是否可以使用泛型類型提前聲明reader
變量,以便可以排除 process_lines() 調用?
let reader: ????;
let input = args.value_of("input").unwrap_or("-");
if input == "-" {
let stdin = io::stdin();
reader = stdin.lock();
} else {
let f = File::open(input).unwrap();
reader = BufReader::new(f);
}
process_lines(reader, re);
或者通過使用將返回impl BufRead + Sized
的(匿名)方法?
就像是:
fn build_reader(input: &str) -> impl BufRead + Sized {
if input == "-" {
let stdin = io::stdin();
stdin.lock()
} else {
let f = File::open(input).unwrap();
BufReader::new(f)
}
}
但是編譯器不是很開心,見https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0e74d3e96de0bbf61b9f61d44d305e5e
編輯
我使用https://stackoverflow.com/a/49964042/258622的建議成功構建了一個 BufRead 構建器
fn build_reader(input: &str) -> Box<dyn BufRead> {
if input == "-" {
Box::new(BufReader::new(io::stdin()))
} else {
let f = File::open(input).unwrap();
Box::new(BufReader::new(f))
}
}
編譯器開心,不知道不使用stdin.lock()
會有什么后果...
主要現在看起來像:
fn main() {
...
let input = args.value_of("input").unwrap_or("-");
let reader = build_reader(input);
process_lines(reader, re)
}
編譯代碼: https : //play.rust-lang.org/? version = stable & mode = debug & edition = 2018 & gist =c5218ef4a266597da6a36c21e060bcda
編輯 2 :利用clap::ArgMatches::value_of()
返回Option<&str>
的事實的更慣用的版本:
fn build_reader(input: Option<&str>) -> Box<dyn BufRead> {
match input {
None => Box::new(BufReader::new(io::stdin())),
Some(filename) => {
let f = File::open(filename).unwrap();
Box::new(BufReader::new(f))
}
}
}
fn main() {
...
let input = args.value_of("input");
let reader = build_reader(input);
process_lines(reader, re)
}
正如@sshashank124 所說,返回impl SomeTrait
僅意味着該函數將返回一種實現SomeTrait
具體類型。 它不提供返回異構類型的功能許可。
Stdin::lock
需要引用的事實在這里也無濟於事。 一旦函數返回或它所在的本地范圍結束,它就會超出范圍。
Stdin::lock
忽略Stdin::lock
的問題,你可以這樣做:
let stdin = io::stdin();
let reader: Box<dyn BufRead> = if input == "-" {
Box::new(stdin.lock())
} else {
let f = File::open(input).unwrap();
Box::new(BufReader::new(f))
};
process_lines(reader, re);
或與第三方箱如either
:
use either::Either;
let stdin = io::stdin();
let reader = if input == "-" {
Either::Left(stdin.lock())
} else {
let f = File::open(input).unwrap();
Either::Right(BufReader::new(f))
};
process_lines(reader, re);
在這種情況下,這似乎微不足道。 但它可能在未來對你有所幫助。
首先,方法方法(使用impl BufRead
)和if/else
方法都行不通,因為兩個BufRead
實現者的類型不同(即StdinLock
和BufReader
)。 這兩種方法的問題在於它們期望單一的具體類型。 我不會太擔心試圖找出像這樣微不足道的東西。
然而,一般來說,如果您希望在運行時具有多態性,您可以使用Box<dyn Trait>
模式來創建一個 trait 對象。 關於這方面的更多信息可以在 Rust 書中找到: https : //doc.rust-lang.org/1.30.0/book/2018-edition/ch17-02-trait-objects.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.