代码之家  ›  专栏  ›  技术社区  ›  gberth

了解rust中“flat_map”与“map”之间的分配细微差别

  •  0
  • gberth  · 技术社区  · 4 年前

    我正在使用代码降临节学习Rust。
    要解决2021年4月4日的问题,我需要解析以下字符串:

    88 67 20 19 15
    22 76 86 44 73
     7 42  6 69 25
    12 68 92 21 75
    97 45 13 52 70
    
    75 98 24 18 77
    17 93 46 49 13
    92 56 97 57 66
    44  0 65 54 74
    23  6 53 42 20
    
    92 94  9 27 41
    73 28 62 90 40
    78  3 12 37 32
     8 86 91 16 30
    84 38 68 11 19
    

    理想情况下,我想生成嵌套向量 Vec<Vec<&str>> .
    我的问题是我不明白为什么下面的代码不起作用。

    let bingo_sheet = grids_str
      split("\r\n\r\n")
      .map(|grid| grid.split_whitespace())
      .collect::<Vec<Vec<&str>>>();
    

    我也不明白货物检查背后的含义。(好吧,这个特征并不存在。但为什么?)

    error[E0277]: a value of type `Vec<Vec<&str>>` cannot be built from an iterator over elements of type `SplitWhitespace<'_>`
      --> src\main.rs:36:10
       |
    36 |         .collect::<Vec<Vec<&str>>>();
       |          ^^^^^^^ value of type `Vec<Vec<&str>>` cannot be built from `std::iter::Iterator<Item=SplitWhitespace<'_>>`
       |
       = help: the trait `FromIterator<SplitWhitespace<'_>>` is not implemented for `Vec<Vec<&str>>`
    

    经过一点实验,这种用法 flat_map 似乎有效。

    let bingo_sheet = grids_str
       .split("\r\n\r\n")
       .flat_map(|grid| grid.split_whitespace())
       .collect::<Vec<&str>>();
    

    我不明白这里发生了什么。
    这个 平面映射(_M) 代码的行为符合预期,但不是 map 密码

    0 回复  |  直到 4 年前
        1
  •  4
  •   Paul    4 年前

    在我写这篇文章的时候,这个问题已经在评论中得到了简短的回答,但也许更详细的版本仍然有帮助!

    我也不明白货物检查背后的含义。(好吧,这个特征并不存在。但为什么?)

    std提供了经常使用的转换,但它并不能为您完成所有转换。

    的呼叫 split_whitespace 返回一个 SplitWhitespace 实现的结构(在本文的其余部分中,我将简单地说“is”) Iterator . 的呼叫 map 返回一个 Map 结构,它是其给定函数的返回类型的迭代器,因此它是字符串切片上的迭代器。

    因为 地图 是一个迭代器,它有一个 collect 方法正如您在文档中看到的,如果存在 B 实现 FromIterator<Self::Item> 这 B 是你的 Vec<Vec<&str>> 和 Self::Item 是的项目 地图 这个 SplitWhiteSpace 结构。所以 收集 是在问,“是吗 Vec<Vec<&str>> 使生效 FromIterator<SplitWhiteSpace> ?, 如果是,我存在,如果不是,我拒绝存在”。

    ( FromIterator<拆分空白> 并不意味着 Vec<T> 可以由 拆分空白 结构,但它可以由某种类型构成 I 它是(或可以成为)项的迭代器 拆分空白 .)

    所以,让我们看看Vec文档,看看是否 Vec<Vec<&str>> 机具 FromIterator<拆分空白> . Vec does implement FromIterator<T> but only for Vec<T> ,所以在您的情况下,它实现 FromIterator<Vec<&str>> 但collect要求它实现 FromIterator<拆分空白> 。事实并非如此,因此您的代码无法编译。

    换句话说,当收集 Map<X> 变成 Vec<Y> ,X必须等于Y。

    这就是为什么添加 collect() 内部 .map 作品因为这使它成为 Map<Vec<&str>> 这意味着类型匹配。 flatmap 也起作用,因为这会创建 FlatMap<&str> 其工作原理与 地图 并且可以收集到 Vec<&str> . ( flat_map 不需要 收集 在其给定函数内部,因为它可以处理内部的迭代器)

    推荐文章