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...
source to share
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.
source to share
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 typeint
, only works because itint
isCopy
) - the second element is bound to
k
((assuming it is of typeint
)
j
and k
thus become temporary copies int
within that element.
source to share