【发布时间】:2021-12-21 12:27:54
【问题描述】:
动机
我想读取光盘上多个文件的值流。这些可能是 CSV 文件,或制表符分隔,或一些专有的二进制格式。因此,我希望处理读取多个文件的函数将Path -> Iterator<Data> 函数作为参数。如果我理解正确,在 Rust 中我需要将迭代器和函数本身装箱,因为它们没有大小。因此我的阅读功能应该是(我只是在这里使用i32 作为我的数据的简单代理):
fn foo(read_from_file: Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>) {
panic!("Not implemented");
}
为了测试,我宁愿不从光盘中读取实际文件。我希望我的测试数据就在测试模块中。这大致是我想要的,但为了简单起见,我只是将它放入 bin 项目的 main 中:
use std::path::Path;
fn foo(read_from_file: Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>) {
panic!("Not implemented");
}
fn main() {
let read_from_file = Box::new(|path: &Path| Box::new(match path.as_os_str().to_str().unwrap() {
"/my_files/data.csv" => vec![1, 2, 3],
"/my_files/data_2.csv" => vec![4, 5, 6],
_ => panic!("Invalid filename"),
}.into_iter()));
foo(read_from_file);
}
错误
这给了我一个编译错误:
Compiling iter v0.1.0 (/home/harry/coding/rust_sandbox/iter)
error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:9:35: 13:19] as FnOnce<(&'r Path,)>>::Output == Box<(dyn Iterator<Item = i32> + 'static)>`
--> src/main.rs:15:9
|
15 | foo(read_from_file);
| ^^^^^^^^^^^^^^ expected trait object `dyn Iterator`, found struct `std::vec::IntoIter`
|
= note: expected struct `Box<(dyn Iterator<Item = i32> + 'static)>`
found struct `Box<std::vec::IntoIter<{integer}>>`
= note: required for the cast to the object type `dyn for<'r> Fn(&'r Path) -> Box<(dyn Iterator<Item = i32> + 'static)>`
For more information about this error, try `rustc --explain E0271`.
error: could not compile `iter` due to previous error
我不太明白。 std::vec::IntoIter 没有实现 Iterator,在这种情况下我不明白为什么这是一个类型错误?
修复,我也不明白
如果我添加显式类型注释Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>,则编译:
use std::path::Path;
fn foo(read_from_file: Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>) {
panic!("Not implemented");
}
fn main() {
let read_from_file : Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>
= Box::new(|path: &Path| Box::new(match path.as_os_str().to_str().unwrap() {
"/my_files/data.csv" => vec![1, 2, 3],
"/my_files/data_2.csv" => vec![4, 5, 6],
_ => panic!("Invalid filename"),
}.into_iter()));
foo(read_from_file);
我很困惑为什么会这样。我对 Rust 的理解是,在 let 定义中,显式类型是可选的 - 除非编译器无法推断它,在这种情况下编译器应该发出 error[E0283]: type annotations required。
【问题讨论】:
-
另一种选择是仅在内部闭包上添加返回类型注释:
Box::new(|path: &Path| -> Box<dyn Iterator<Item = _>> { Box::new(... ) }) -
我确定在某处我找不到重复项,但
Box<T>和Box<dyn Trait>在 Rust 中是完全不同的东西,并且具有不同的内存布局。如果您只是将Iterator的某个实例装箱,它不会是Box<dyn Iterator>。您必须将其转换为一个。