1

I can't get this code to compile:

fn main() {
  let grid: [[Option<i32>;2];2] = [
    [Some(1),Some(2)],
    [None,Some(4)],
  ];

  for row in grid.iter() {
    for v in row.iter() {
      match v {
        Some(x) => print!("{}", x),
        None => print!(" "),
      }
    }
    print!("\n");
  }
}

I get this error message

   Compiling array-2d v0.1.0 (file:///Users/paul/src/test/rust/array-2d)
src/main.rs:8:5: 13:6 error: type mismatch resolving `<core::slice::Iter<'_, core::option::Option<i32>> as core::iter::Iterator>::Item == core::option::Option<_>`:
 expected &-ptr,
    found enum `core::option::Option` [E0271]
src/main.rs: 8     for v in row.iter() {
src/main.rs: 9       match v {
src/main.rs:10         Some(x) => print!("{}", x),
src/main.rs:11         None => print!(" "),
src/main.rs:12       }
src/main.rs:13     }
src/main.rs:8:5: 13:6 note: in this expansion of for loop expansion
src/main.rs:7:3: 15:4 note: in this expansion of for loop expansion
src/main.rs:8:5: 13:6 help: run `rustc --explain E0271` to see a detailed explanation
error: aborting due to previous error
Could not compile `array-2d`.

Can someone interpret that to tell me what I'm doing wrong?

6
  • Note that the Rust style is 4-space indents. Additionally, the type annotation isn't needed, spaces come after commas, and you usually would see for x in &collection. Example. Commented Dec 2, 2015 at 18:54
  • Can you explain why for row in &grid lets me leave off the .iter()? Commented Dec 2, 2015 at 18:59
  • Make sure you are familiar with The Rust Programming Language sections on iterators and loops. The missing piece is that the for loop expression must adhere to IntoIterator, which is automatically called. You'll note that IntoIterator is implemented for references to arrays and slices. Commented Dec 2, 2015 at 19:11
  • FWIW, I've submitted a PR that clarifies that IntoIterator is used for for loops. Commented Dec 2, 2015 at 19:18
  • So you're saying a trait can be implemented for a reference to T but not for T itself? That is a new concept to me. Really? Commented Dec 2, 2015 at 19:25

1 Answer 1

1

Simple. You're just missing that v is a reference.

pub fn main() {
  let grid: [[Option<i32>;2];2] = [
    [Some(1),Some(2)],
    [None,Some(4)],
  ];

  for row in grid.iter() {
    for &v in row.iter() {
      match v {
        Some(x) => print!("{}", x),
        None => print!(" "),
      }
    }
    print!("\n");
  }

  // Keep in mind that i32 is Copy (but Option is not)
  // and an Array of X is Copy if X is Copy,
  // So there is no need to borrow v here, as follows:
  let grid2: [[i32;2];2] = [
    [1,2],
    [0,4],
  ];

  for row in grid2.iter() {
    for v in row.iter() {
      print!("{}", v);
    }
    print!("\n");
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! So a follow-up question: I can't say for row in grid (no .iter()), but I can say for &v in row. Why is .iter() optional in the second line but not the first?
Because you can Copy an array rather than making a reference to it, as long as the contents of the array also implement Copy. i32 implements Copy, but Optional doesn't, so you can copy an [i32; 2] without any extra syntax but not an [Optional<i32>; 2].
I'm talking about the inner loop in the original code (with Optional). Why is .iter() required for the outer loop but not the inner loop? I think @Shepmaster answered it above by saying that IntoIterator is implemented by references to arrays but not arrays. Does that sound right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.