iterator - 提取对辅助函数的迭代器调用链

标签 iterator rust

<分区>

我正在尝试编写一个函数来封装一系列链式迭代器方法调用 (.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_linesinput 错误。还有一个变化:

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 _)
}

现在您只需处理警告。

简而言之:阅读编译器消息。它们很有用。

关于iterator - 提取对辅助函数的迭代器调用链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47204707/

相关文章:

rust - 在 Gitlab CI 中缓存 Rust/Wasm 工具?

c++ - 关于模板函数实例化的编译时错误

rust - Rust#![no_std] : unresolved external symbol _mainCRTStartup

generics - 如何创建包含更高维度的代数矩阵的结构?

rust - 线程中产生的循环不应该重复打印吗?

rust - 如何在 gtk-rs 中监听剪贴板 "owner-change"事件?

c# - if(items != null) 在 foreach(T item in items) 之前是否多余?

reference - 在 Rust 中,为什么 std::iter::Iterator 的 min 函数返回一个引用?

java - 类和迭代器接口(interface)之间的关系

c++ - Visual C++ 无法编译 vector insert()