Why does iterating a vector of i32s give references to i32 (&i32)?

时光毁灭记忆、已成空白 提交于 2020-07-03 11:44:07

问题


The following program tries to grade the marks of a student:

use std::io;

fn main() {
    let mut in0 = String::new();
    io::stdin().read_line(&mut in0).expect("stdin err");
    let n: i32 = in0.trim().parse().expect("parse err");
    println!("{}", n);
    let mut v: Vec<i32> = Vec::new();
    for _ in 0..n {
        let mut inp = String::new();
        io::stdin().read_line(&mut inp).expect("stdin err");
        let num: i32 = inp.trim().parse().unwrap();
        v.push(num);
    }
    let out: Vec<_> = v
        .iter()
        .map(|x| {
            if x < 38 {
                x
            } else if x % 5 > 3 {
                x + x % 5
            } else {
                x
            }
        })
        .collect();
    println!("{:?}", v);
}

While compiling, I get the following error.

error[E0308]: mismatched types
  --> src/main.rs:19:20
   |
19 |             if x < 38 {
   |                    ^^
   |                    |
   |                    expected `&i32`, found integer
   |                    help: consider borrowing here: `&38`

error[E0308]: `if` and `else` have incompatible types
  --> src/main.rs:24:17
   |
21 |               } else if x % 5 > 3 {
   |  ____________________-
22 | |                 x + x % 5
   | |                 --------- expected because of this
23 | |             } else {
24 | |                 x
   | |                 ^ expected `i32`, found `&i32`
25 | |             }
   | |_____________- `if` and `else` have incompatible types
   |
help: consider dereferencing the borrow
   |
23 |             } else *{
24 |                 x
25 |             }

How is the x variable a &i32 type and not a i32 type?


回答1:


Calling the .iter() method on a vector returns an iterator over references the vector's elements. Otherwise, it would have to move or copy the elements out of the vector, which is not desirable in the general case [1]. In the documentation this is not immediately obvious from the declaration:

pub fn iter(&self) -> Iter<T>  // Return type does not look like a reference

However, the examples show that you get a reference:

assert_eq!(iterator.next(), Some(&1));  // note the `&1` instead of just `1`

The closure can be instructed to dereference the parameter:

v.iter().map(|&x| { /* do something */ })

This is fine if the vector contains Copyable types like i32. Otherwise this would result in a cannot move out of borrowed content error. In this case you will likely want to work with a reference anyway.

[1] Moving would clear the vector, which is covered by the .drain() method, and copying is not possible/efficient on all types.




回答2:


If you want to consume the Vec, you must use into_iter() method:

use std::io;

fn main() {
    let mut in0 = String::new();
    io::stdin().read_line(&mut in0).expect("stdin err");
    let n: i32 = in0.trim().parse().expect("parse err");
    println!("{}", n);
    let mut v: Vec<i32> = Vec::new();
    for _ in 0 .. n {
        let mut inp = String::new();
        io::stdin().read_line(&mut inp).expect("stdin err");
        let num: i32 = inp.trim().parse().unwrap();
        v.push(num);
    }
    let out: Vec<_> = v.into_iter().map(|x| {
        if x < 38 {
            x
        } else if x % 5 > 3 {
            x + x % 5
        } else {
            x
        }
    }).collect();
    println!("{:?}", out);
}

If you do not consume the vector, the things inside it can only be borrowed, not moved.



来源:https://stackoverflow.com/questions/48985903/why-does-iterating-a-vector-of-i32s-give-references-to-i32-i32

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!