问题
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 Copy
able 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