在 Rust 中的 iter 上使用 map 时,“无法推断 `_` 的类型”

Posted

技术标签:

【中文标题】在 Rust 中的 iter 上使用 map 时,“无法推断 `_` 的类型”【英文标题】:"cannot infer type for `_`" when using map on iter in Rust 【发布时间】:2017-03-18 03:58:29 【问题描述】:

我遇到了一个问题,我试图用随机真/假值初始化一个二维布尔数组,但编译器似乎无法推断出我需要的类型;我只是想知道我需要为推理引擎指定什么才能解决这个问题。

extern crate rand;

fn main() 
    let mut grid = [[false; 10]; 10];
    grid.iter_mut().map(|row|  [false; 10].iter().map(|_|  rand::random() ).collect() );

游乐场link(没有rand::random()

我得到的错误是

   | grid.iter_mut().map(|row|  [false; 10].iter().map(|_|  rand::random() ).collect() );
   |                 ^^^ cannot infer type for `_`

【问题讨论】:

好吧,您不妨阅读collect() 上的文档。一旦你理解了为什么不能推断闭包的返回类型,你仍然无法收集到一个大小合适的数组中。之后你能相应地改写问题吗? 抛开性能不谈,您可能想要获取Rng 并重复使用它,而不是一遍又一遍地获取线程本地RNG。 【参考方案1】:

由于[T; 10]类型实现了Rand where T: Rand,所以可以直接使用rand::random()

extern crate rand;

fn main() 
    let grid: [[bool; 10]; 10] = rand::random();
    println!(":#?", grid);


至于为什么在您的示例中类型推断失败 - 这里有一些稍微简单的说明问题:

fn main() 
    let mut arr = [false; 10];
    let mapped = arr.iter_mut().map(|_| rand::random()).collect();
    println!(":?", arr);
    println!(":?", mapped);

给出错误:

error[E0282]: unable to infer enough type information about `_`
 --> src/main.rs:5:13
  |
5 |         let mapped = arr.iter_mut().map(|_| rand::random()).collect();
  |             ^^^^^^ cannot infer type for `_`
  |
  = note: type annotations or generic parameter binding required

所以我们可以指定类型:

fn main() 
    let mut arr = [false; 10];
    let mapped = arr.iter_mut().map(|_| rand::random()).collect::<[bool; 10]>();
    println!(":?", arr);
    println!(":?", mapped);

注意在 collect 之后使用 "turbofish" 运算符 ::&lt;&gt; 来指定要收集到的类型,在本例中为 ::&lt;[bool; 10]&gt;。不幸的是,编译器会在这里抱怨:

error[E0277]: the trait bound `[_; 10]: std::iter::FromIterator<bool>` is not satisfied

那么std::iter::FromIterator&lt;bool&gt; 是什么?好吧,考虑collect 函数的定义:

fn collect<B>(self) -> B
    where B: FromIterator<Self::Item>

这意味着你收集到的任何类型都需要实现FromIterator&lt;Self::Item&gt;。不幸的是,数组没有实现FromIterator——但是有很多可能的类型可以实现,例如VecVecDequeHashSetBTreeSet等等。所以我们可以修改示例:

fn main() 
    let mut arr = [false; 10];
    let mapped = arr.iter_mut().map(|_| rand::random()).collect::<Vec<bool>>();
    println!(":?", arr);
    println!(":?", mapped);

但是,这可能不会给您想要的结果:

[false, false, false, false, false, false, false, false, false, false]
[true, false, false, true, true, false, true, false, true, true]

那是什么?为什么arr 没有发生突变,即使它被声明为可变的,而我们使用了iter_mut?原因是map 从现有对象中生成了一个 new 对象——它没有“就地”映射。如果您真的想就地映射,可以使用以下内容:

fn main() 
    let mut arr = [false; 10];
    let mapped = arr.iter_mut().map(|b| *b = rand::random()).collect::<Vec<()>>();
    println!(":?", arr);
    println!(":?", mapped);

产量

[true, false, true, true, true, false, false, false, true, true]
[(), (), (), (), (), (), (), (), (), ()]

但是,这种迭代器的使用被认为是单调的(更不用说令人困惑了)——惯用的方法是使用 for 循环:

fn main() 
    let mut arr = [false; 10];
    for b in &mut arr 
        *b = rand::random();
    
    println!(":?", arr);

[false, true, true, true, false, false, true, false, true, false]

好多了。当然在这种特殊情况下,我的第一个例子可能是要走的路。

【讨论】:

以上是关于在 Rust 中的 iter 上使用 map 时,“无法推断 `_` 的类型”的主要内容,如果未能解决你的问题,请参考以下文章

“未处理的异常:NoSuchMethodError:在 null 上调用了 getter 'iterator'。”当我在颤振中使用 google_maps_polyline 插件时抛出

Hadoop Map Reduce - Iterable上的嵌套循环 reduce中的值忽略将文本写入上下文时的文本结果

了解收集 `flat_map` 与收集 rust 中的 `map` 之间的细微差别

rust - 如何在Vec上更新或插入?

为啥 map over 一个 iterable 返回一个一次性的 iterable?

C++ STL中的 iterator 和 const_iterator