在Rust中使用map时,"无法推断出`_`"的类型

dav*_*ave 7 arrays inference rust

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

extern crate rand;

fn main() {
    let mut grid = [[false; 10]; 10];
    grid.iter_mut().map(|row| { [false; 10].iter().map(|_| { rand::random() }).collect() });
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接(不含rand::random())

我得到的错误是

   | grid.iter_mut().map(|row| { [false; 10].iter().map(|_| { rand::random() }).collect() });
   |                 ^^^ cannot infer type for `_`
Run Code Online (Sandbox Code Playgroud)

Djz*_*zin 7

由于类型[T; 10]实现的Rand地方T: Rand,你可以rand::random()直接使用:

extern crate rand;

fn main() {
    let grid: [[bool; 10]; 10] = rand::random();
    println!("{:#?}", grid);
}
Run Code Online (Sandbox Code Playgroud)

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

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

给出错误:

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
Run Code Online (Sandbox Code Playgroud)

所以我们可以指定类型:

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

注意在收集之后使用"turbofish"运算符::<>来指定要收集的类型,在这种情况下::<[bool; 10]>.不幸的是,编译器会抱怨:

error[E0277]: the trait bound `[_; 10]: std::iter::FromIterator<bool>` is not satisfied
Run Code Online (Sandbox Code Playgroud)

那是什么std::iter::FromIterator<bool>?那么,考虑collect函数的定义:

fn collect<B>(self) -> B
    where B: FromIterator<Self::Item>
Run Code Online (Sandbox Code Playgroud)

这意味着您需要实现的任何类型FromIterator<Self::Item>.阵列不,不幸的是,实施FromIterator-但也有许多可能的类型做,例如Vec,VecDeque,HashSet,BTreeSet等等.所以我们可以修改这个例子:

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

但是,这可能无法为您提供您希望的结果:

[false, false, false, false, false, false, false, false, false, false]
[true, false, false, true, true, false, true, false, true, true]
Run Code Online (Sandbox Code Playgroud)

什么给出了什么?为什么不是arr变异,即使它被宣布为可变,我们用过iter_mut?原因是从现有对象map生成一个对象 - 它不映射"就地".如果您确实想要就地映射,可以使用以下内容:

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

生产

[true, false, true, true, true, false, false, false, true, true]
[(), (), (), (), (), (), (), (), (), ()]
Run Code Online (Sandbox Code Playgroud)

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

fn main() {
    let mut arr = [false; 10];
    for b in &mut arr {
        *b = rand::random();
    }
    println!("{:?}", arr);
}
Run Code Online (Sandbox Code Playgroud)
[false, true, true, true, false, false, true, false, true, false]
Run Code Online (Sandbox Code Playgroud)

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