簡體   English   中英

Rust 通用局部變量

[英]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實現者的類型不同(即StdinLockBufReader )。 這兩種方法的問題在於它們期望單一的具體類型。 我不會太擔心試圖找出像這樣微不足道的東西。

然而,一般來說,如果您希望在運行時具有多態性,您可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM