一个简单的程序,我要做的是从文件中获取行,或者如果文件不存在,则传入一个零长度迭代器:
use std::fs::File;
use std::io::{self, BufRead};
fn run_against_input(inp: &mut dyn Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let input: dyn Iterator<Item = String> = match file {
Ok(f) => io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => Vec::new().into_iter()
};
run_against_input(&mut dyn input);
}
当我这样做时,我会得到以下错误:
Compiling playground v0.0.1 (/playground)
error: expected expression, found keyword `dyn`
--> src/main.rs:19:28
|
19 | run_against_input(&mut dyn input);
| ^^^ expected expression
error[E0308]: mismatched types
--> src/main.rs:13:18
|
13 | Ok(f) => io::BufReader::new(f).lines()
| __________________^
14 | | .map(|line| line.unwrap()),
| |______________________________________^ expected trait object `dyn Iterator`, found struct `Map`
|
= note: expected trait object `dyn Iterator<Item = String>`
found struct `Map<std::io::Lines<BufReader<File>>, [closure@src/main.rs:14:18: 14:38]>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 2 previous errors
我确实特别需要&mut
引用我正在编写的代码中的Iterator
(这是我面临的问题的一个小复制(,但我想这与手头的问题无关。我看到Map
的Iterator
上有一个impl
,但我得到的错误是这不是Iterator<Item = String>
的trait对象。我也试过这个:
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => &mut io::BufReader::new(f).lines()
.map(|line| line.unwrap()),
Err(_) => &mut Vec::new().into_iter()
};
这当然不起作用,因为在我返回引用的语句中删除了临时值(这就是为什么我按照编译器的建议做了let
绑定的事情(。
编辑链接到操场-https://play.rust-lang.org/?version=stable&mode=调试&edition=2021&gist=99b8105cc266e03db2d92cc22610962
您可以将每个分支的迭代器保存在match
之外的一个单独变量中(也可以使用std::iter::empty()
而不是Vec::new().into_iter()
(:
use std::fs::File;
use std::io::{self, BufRead};
use std::iter;
fn run_against_input(inp: impl Iterator<Item = String>) {
for i in inp {
println!("Input line: {}", i);
}
}
fn main() {
let file = File::open("data.txt");
let mut lines;
let mut no_lines;
let input: &mut dyn Iterator<Item = String> = match file {
Ok(f) => {
lines = io::BufReader::new(f).lines().map(Result::unwrap);
&mut lines
},
Err(_) => {
no_lines = iter::empty();
&mut no_lines
},
};
run_against_input(input);
}
您可以使用Box
而不是引用,因此该值是拥有的,不会被丢弃:
let mut input: Box<dyn Iterator<Item = String>> = match file {
Ok(f) => Box::new(io::BufReader::new(f).lines().map(|line| line.unwrap())),
Err(_) => Box::new(Vec::new().into_iter()),
};
操场
如果你喜欢,你也可以改变你的功能,用一个盒子代替一个参考:
fn run_against_input(inp: Box<dyn Iterator<Item = String>>) {