动机
我想要读取多个磁盘文件中的值流。这些文件可能是CSV文件,也可能是制表符分隔,或者会采用某些专有二进制格式。因此我希望处理多个文件的函数能够将 Path -> Iterator<Data>
函数作为参数传递进来。如果我理解正确的话,在Rust中我需要将这个迭代器和函数封装起来,因为它们是不确定大小的。因此我的读取函数应该是这样的(这里只是使用 i32
作为数据的简单代理):
fn foo(read_from_file: Box<dyn Fn(&Path) -> Box<dyn Iterator<Item=i32>>>) {
panic!("Not implemented");
}
为了测试,我不想从磁盘上读取实际文件。我希望我的测试数据就在测试模块中。以下是我想要的大致内容,但出于简单起见,我将其放入了bin项目的主体中:
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(...)})
。 - PitaJBox<T>
和Box<dyn Trait>
是根本不同的东西,并且具有不同的内存布局。如果你只是将某个Iterator
实例装箱,则它不会成为Box<dyn Iterator>
。你必须将其转换为一个。 - Aplet123