For a hinge in rust - a precise definition?

I'm new to rust from a C (and to a lesser extent C ++) background - I've been trying rust from an overnight build since 28 Nov 2014. I wrote the following piece of code:

fn main() {
  let my_array = [1i, 2i, 3i];
  let print_me = |j| { println!("= {}", j) };
  for k in my_array.iter() {
    print_me(k)
  }
}

      

This worked (compiled and run) as expected. But then I specified the type of the argument passed to the closure print_me

like this:

fn main() {
  let my_array = [1i, 2i, 3i];
  let print_me = |j: int| { println!("= {}", j) };
  for k in my_array.iter() {
    print_me(k)
  }
}

      

I got a compilation error:

mismatched types: expected `int`, found `&int` (expected int, found &-ptr)
  print_me(k)
           ^

      

Now this confused me (and like many newbies, I started to wonder if this was a bug in a nightly build) until I tried this (changed k

to &k

in instructions for

):

fn main() {
  let my_array = [1i, 2i, 3i];
  let print_me = |j: int| { println!("= {}", j) };
  for &k in my_array.iter() {
    print_me(k)
  }
}

      

Everything went perfectly. So I seem to have misunderstood the "for" syntax itself - or maybe the exact operation of the iterator - or maybe the syntax for using the vis-a-vis reference to a pointer [which is linked but different in C ++].

Can anyone point me to the right place for this kind of information? In particular, the design for A in B { C1; C2; ... Cn }

must exist A

and B

?

Many thanks...

+3


source to share


2 answers


First of all, here's a link to the definition for

in the link
.

To summarize, B

it is any expression that evaluates to something that implements a trait Iterator<T>

, whereas it A

is an irrefutable pattern that binds values โ€‹โ€‹of a type T

.

In your particular case, [int]::iter

returns Items<int>

that implements Iterator<&int>

(scroll down to the Feature Implements section to find it). That is, he does not give int

s, he gives &int

s.



So, in both the first and second examples, it k

actually binds to &int

s, not int

s. When you specified the type of closure, you actually specified the wrong type. The reason the last example works is because A

is a template, not a variable name. What it really does &k

is "destructuring" &int

, which binds the part int

to a variable named k

.

The "irrefutable" part simply means that the template should always work. For example, you cannot do for Some(x) in thingy

where thingy

implements Iterator<Option<_>>

; Some(x)

will not necessarily be valid for every element of the iterator; thus, it is a rebuttable pattern.

+7


source


Most iterators actually return a reference, not a value. Of course, you need to check the return type .iter()

, which should be Iterator<X>

: X

will be the return type of the variable.

So here:

fn main() {
  let my_array = [1i, 2i, 3i];
  let print_me = |j: int| { println!("= {}", j) };
  for k in my_array.iter() {
    print_me(k)
  }
}

      

It X

is &int

(referenced to int

), and therefore k

has a type &int

.

This is why it throws print_me

an error when called : &int

passed where int

expected.


There are two possible errors here: the first solution is to specify a different type print_me

:

let print_me = |j: &int| { println!("= {}", j) };

      

And the second is to change the type k

by destructuring in a loop:



for &k in my_array.iter() { ... }

      

The destructuring happens because it for .. in

accepts an irrefutable pattern, so you can match patterns just like you would in an expression match

, except that the type of the variable must match (otherwise, you get a compiler-time error).

To better illustrate this, we can use a slightly more complex example:

fn main() {
  let my_array = [(1i, 2i), (2, 3), (3, 4)];
  let print_me = |a: int, b: int| { println!("= {} {}", a, b) };
  for &(j, k) in my_array.iter() {
    print_me(j, k)
  }
}

      

Type my_array

- [(int, int)]

: array of 2 tuples int

. Hence, the result .iter()

is of type Iterator<&(int, int)>

: an iterator to a reference to a tuple 2 int

aka &(int, int)

.

When we use an irrefutable pattern &(j, k)

, what happens is that we destroy the tuple so that:

  • the first element is bound to j

    (assuming it is of type int

    , only works because it int

    is Copy

    )
  • the second element is bound to k

    ((assuming it is of type int

    )

j

and k

thus become temporary copies int

within that element.

+4


source







All Articles