Oh, I think I misread your post. Youâre asking why writing for &elem in ...
instead of for elem in ...
turns &String
into String
instead of &&String
. As I mentioned above thatâs due to how &
works in patterns.
This is analogous to something like
struct Foo<T>(T);
let x = Foo(42);
// x is `Foo<i32>`
let Foo(y) = x;
// y is `i32` and not `Foo<Foo<i32>>
Patterns usually do kind-of âthe oppositeâ of expressions, so we have
let x = &42;
// x is `&i32`
let &y = x;
// y is `i32` and not `&&i32`
Also, as mentioned above, this doesnât actually work for String
like that. The assignment let &y = x;
copies the value 42
into y
.
for
loops are similar to let
expressions:
struct Foo<T>(T);
let x = vec![Foo(42), Foo(69)];
// x is Vec<Foo<42>>`
for y in x.iter() {
// y is &Foo<42>
}
for &y in x.iter() {
// y is Foo<42>
}
for &Foo(y) in x.iter() {
// y is 42
}
Thereâs also more to pattern than this, in particular you can re-introduce the indirection with something like ref
, as in
struct Foo<T>(T);
let x = vec![Foo(42), Foo(69)];
// x is Vec<Foo<42>>`
for &Foo(ref y) in x.iter() {
// y is &42
}
This has the benefit that it avoids the need to copy the type and it also works with something like String
again:
struct Foo<T>(T);
let x = vec![Foo("hello".to_string()), Foo("world".to_string())];
// x is Vec<Foo<String>>`
for &Foo(ref y) in x.iter() {
// y is &String
}
/* this wouldnât work:
for &Foo(y) in x.iter() {
// y would have to be String
}
*/
Patterns like &Foo(ref x)
had become so common in earlier Rust versions that thereâs a shorter syntax for them
struct Foo<T>(T);
let x = vec![Foo("hello".to_string()), Foo("world".to_string())];
// x is Vec<Foo<String>>`
for &Foo(ref y) in x.iter() {
// y is &String
}
// the above is equivalent to:
for Foo(y) in x.iter() {
// y is &String
}
To clarify, the ref
in the above examples does exactly what you seem to have expected &
do to, in particular if you try
let list = vec![String::from("Alice"), String::from("Bob"), String::from("Catherine")];
for ref elem in list.iter() {
println!("{}", elem == true) // Type of elem is String
}
youâll see that now elem
is &&String
. Of course introducing an extra reference level in this situation is relatively useless, youâll probably never see anyone write something like for ref elem in ...
ever.