我正在尝试编写一个函数来封装一系列链式迭代器方法调用 (.lines().map(...).filter(...)
)目前有重复。我无法弄清楚类型签名来编译它。如果这对于 Rust 来说是不可能的或非常不惯用的,我愿意接受有关惯用方法的建议。
use std::fs;
use std::io;
use std::io::prelude::*;
use std::iter;
const WORDS_PATH: &str = "/usr/share/dict/words";
fn is_short(word: &String) -> bool {
word.len() < 7
}
fn unwrap(result: Result<String, io::Error>) -> String {
result.unwrap()
}
fn main_works_but_code_dupe() {
let file = fs::File::open(WORDS_PATH).unwrap();
let reader = io::BufReader::new(&file);
let count = reader.lines().map(unwrap).filter(is_short).count();
println!("{:?}", count);
let mut reader = io::BufReader::new(&file);
reader.seek(io::SeekFrom::Start(0));
let sample_size = (0.05 * count as f32) as usize; // 5% sample
// This chain of iterator logic is duplicated
for line in reader.lines().map(unwrap).filter(is_short).take(sample_size) {
println!("{}", line);
}
}
fn short_lines<'a, T>
(reader: &'a T)
-> iter::Filter<std::iter::Map<std::io::Lines<T>, &FnMut(&str, bool)>, &FnMut(&str, bool)>
where T: io::BufRead
{
reader.lines().map(unwrap).filter(is_short)
}
fn main_dry() {
let file = fs::File::open(WORDS_PATH).unwrap();
let reader = io::BufReader::new(&file);
let count = short_lines(reader).count();
println!("{:?}", count);
// Would like to do this instead:
let mut reader = io::BufReader::new(&file);
reader.seek(io::SeekFrom::Start(0));
let sample_size = (0.05 * count as f32) as usize; // 5% sample
for line in short_lines(reader).take(sample_size) {
println!("{}", line);
}
}
fn main() {
main_works_but_code_dupe();
}
I can't figure out the type signatures to get this to compile.
编译器告诉您它是什么。
error[E0308]: mismatched types
--> src/main.rs:35:5
|
35 | reader.lines().map(unwrap).filter(is_short)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found fn item
|
= note: expected type `std::iter::Filter<std::iter::Map<_, &'a for<'r> std::ops::FnMut(&'r str, bool) + 'a>, &'a for<'r> std::ops::FnMut(&'r str, bool) + 'a>`
found type `std::iter::Filter<std::iter::Map<_, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String {unwrap}>, for<'r> fn(&'r std::string::String) -> bool {is_short}>`
当然,您不能直接复制+粘贴它。您必须将 _
类型替换为您已经拥有的实际类型(因为它已经正确,所以将其排除在外)。其次,您需要删除{unwrap}
和{is_short}
位;这是因为函数项具有独特的类型,这就是编译器注释它们的方式。遗憾的是,您实际上无法写出这些类型。
重新编译并...
error[E0308]: mismatched types
--> src/main.rs:35:5
|
32 | -> std::iter::Filter<std::iter::Map<std::io::Lines<T>, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String>, for<'r> fn(&'r std::string::String) -> bool>
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- expected `std::iter::Filter<std::iter::Map<std::io::Lines<T>, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String>, for<'r> fn(&'r std::string::String) -> bool>` because of return type
...
35 | reader.lines().map(unwrap).filter(is_short)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
|
= note: expected type `std::iter::Filter<std::iter::Map<_, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String>, for<'r> fn(&'r std::string::String) -> bool>`
found type `std::iter::Filter<std::iter::Map<_, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String {unwrap}>, for<'r> fn(&'r std::string::String) -> bool {is_short}>`
还记得我说过功能项具有唯一类型吗?是的,那个。为了修复那个,我们从函数项转换为函数指针。我们甚至不需要指定我们要转换的目标,我们只需要让编译器知道我们希望它进行转换。
fn short_lines<'a, T>
(reader: &'a T)
-> std::iter::Filter<std::iter::Map<std::io::Lines<T>, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String>, for<'r> fn(&'r std::string::String) -> bool>
where T: io::BufRead
{
reader.lines().map(unwrap as _).filter(is_short as _)
}
error[E0308]: mismatched types
--> src/main.rs:41:29
|
41 | let count = short_lines(reader).count();
| ^^^^^^ expected reference, found struct `std::io::BufReader`
|
= note: expected type `&_`
found type `std::io::BufReader<&std::fs::File>`
= help: try with `&reader`
同样,编译器会准确地告诉您要做什么。进行更改并...
error[E0507]: cannot move out of borrowed content
--> src/main.rs:35:5
|
35 | reader.lines().map(unwrap as _).filter(is_short as _)
| ^^^^^^ cannot move out of borrowed content
对,那是因为你的short_lines
的input 错误。还有一个变化:
fn short_lines<T>
(reader: T)
-> std::iter::Filter<std::iter::Map<std::io::Lines<T>, fn(std::result::Result<std::string::String, std::io::Error>) -> std::string::String>, for<'r> fn(&'r std::string::String) -> bool>
where T: io::BufRead
{
reader.lines().map(unwrap as _).filter(is_short as _)
}
现在您只需处理警告。
简而言之:阅读编译器消息。它们很有用。