[英]Rust generic local variable
From the book "Rust in Action" (Manning, currently MEAP), the final example of Chapter 2 shows a way to implement a generic function that can work on BufRead + Sized
parameters:从《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 => (),
}
}
}
The code that uses it looks like:使用它的代码如下所示:
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);
}
I'm wondering if it is possible to declare the reader
variable earlier with a generic type so the process_lines() call can be factored out?我想知道是否可以使用泛型类型提前声明
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);
Or by using an (anonymous) method that would return impl BufRead + Sized
?或者通过使用将返回
impl BufRead + Sized
的(匿名)方法?
Something like:就像是:
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)
}
}
But compiler is not very happy, see https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0e74d3e96de0bbf61b9f61d44d305e5e但是编译器不是很开心,见https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0e74d3e96de0bbf61b9f61d44d305e5e
Edit编辑
I succeeded building a BufRead builder using the advice from https://stackoverflow.com/a/49964042/258622我使用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))
}
}
Compiler is happy, I wonder what are the consequences of not using stdin.lock()
...编译器开心,不知道不使用
stdin.lock()
会有什么后果...
Main now looks like:主要现在看起来像:
fn main() {
...
let input = args.value_of("input").unwrap_or("-");
let reader = build_reader(input);
process_lines(reader, re)
}
Code that compiles: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c5218ef4a266597da6a36c21e060bcda编译代码: https : //play.rust-lang.org/? version = stable & mode = debug & edition = 2018 & gist =c5218ef4a266597da6a36c21e060bcda
Edit 2 : A more idiomatic version taking advantage of the fact that clap::ArgMatches::value_of()
returns an Option<&str>
:编辑 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)
}
As @sshashank124 has stated, returning impl SomeTrait
only means the function is to return one concrete type that implements SomeTrait
.正如@sshashank124 所说,返回
impl SomeTrait
仅意味着该函数将返回一种实现SomeTrait
具体类型。 It doesn't give the function license to return heterogeneous types.它不提供返回异构类型的功能许可。
The fact that Stdin::lock
takes a reference also doesn't help here. Stdin::lock
需要引用的事实在这里也无济于事。 It will go out of scope as soon as the function returns or the local scope which it is in ends.一旦函数返回或它所在的本地范围结束,它就会超出范围。
Ignore the issue of Stdin::lock
for a moment, you can do: 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);
Or with third party crate such as either
:或与第三方箱如
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);
It seems trivial in this case.在这种情况下,这似乎微不足道。 But it may help you in the future.
但它可能在未来对你有所帮助。
Firstly, the method approach (with impl BufRead
) nor the if/else
approach will work since the types of the two BufRead
implementers are different (namely StdinLock
and BufReader
).首先,方法方法(使用
impl BufRead
)和if/else
方法都行不通,因为两个BufRead
实现者的类型不同(即StdinLock
和BufReader
)。 The issue with both of these methods is that they expect a single concrete type.这两种方法的问题在于它们期望单一的具体类型。 I wouldn't worry too much about trying to factor out something as trivial as this.
我不会太担心试图找出像这样微不足道的东西。
In general however, if you wish to have polymorphism at runtime, you can use the Box<dyn Trait>
pattern to create a trait object.然而,一般来说,如果您希望在运行时具有多态性,您可以使用
Box<dyn Trait>
模式来创建一个 trait 对象。 More information on this can be found in the rust book here: https://doc.rust-lang.org/1.30.0/book/2018-edition/ch17-02-trait-objects.html关于这方面的更多信息可以在 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.