Reputation: 304
My understanding:
iter()
: read only view of data inside collection.into_iter()
: writable and readable view of data inside collection.
(caveat : full access but moved from parent scope)iter_mut()
: writable view of data inside collection.
(caveat : full access but not moved from parent scope, similar to other gc collected languages)And just to differentiate datatypes returned from iter()
and iter_mut()
, we do &"Ferris"
and &mut"Ferris"
Working code :
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter_mut() {
*name = match name {
&mut "Ferris" => "There is a rustacean among us!",
_ => "Hello!",
}
}
println!("names: {:?}", names);
}
Why the below code is not working.
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.into_iter() {
*name = match name {
"Ferris" => "There is a rustacean among us!",
_ => "Hello",
};
println!("names: {:?}", names);
}
}
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
src/main.rs:6:25
|
6 | "Ferris" => "There is a rustacean among us!",
expected `str`, found `&str`
error[E0277]: the size for values of type `str` cannot be known at compilation time
src/main.rs:5:9
|
5 | *name = match name {
doesn't have a size known at compile-time
|
help: the trait `Sized` is not implemented for `str`
note: the left-hand-side of an assignment must have a statically known size
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 2 previous errors
I tried changing the &str
to String
using to_string()
inside match statement but it's not clear why this code is not working.
Upvotes: 1
Views: 334
Reputation: 27498
To understand the error you can look at the types, names
is a Vec
created from string literals, so it's type is Vec<&'static str>
. Now the item of it's into_iter()
iterator is &'static str
, when you try do dereference that, i.e. write to *name
like your code tries, it has to dereference &'static str
, the result is str
an unsized type! You could instead write to name
but you'd have to make its binding mutable, of course into_iter
moves it's receiver, the vector, so you cannot print it after that call so the result doesn't do all that much:
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for mut name in names.into_iter() {
name = match name {
"Ferris" => "There is a rustacean among us!",
_ => "Hello",
};
}
}
into_iter
called on collections, does not give you a "view" to some data, instead, it gives you the data directly, no pointer or other indirection, that's why dereferencing its items generally doesn't make sense (the big exception being when the collection contains pointers)
Here is an Overview of how the different *iter*
methods work
Upvotes: 1
Reputation: 502
Types are not the same depending on your iteration.
In particular name in names.into_iter()
will not give you a mutable reference but the type inside collection names
, that is &str
.
Following code [playground]:
fn type_name<T>(_t: &T) -> &'static str {
std::any::type_name::<T>()
}
fn main() {
let mut names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter_mut() {
println!("names: {:?} -> {}", name, type_name(&name));
}
for name in names.iter() {
println!("names: {:?} -> {}", name, type_name(&name));
}
for name in names.into_iter() {
println!("names: {:?} -> {}", name, type_name(&name));
}
}
will give you:
names: "Bob" -> &mut &str
names: "Frank" -> &mut &str
names: "Ferris" -> &mut &str
names: "Bob" -> &&str
names: "Frank" -> &&str
names: "Ferris" -> &&str
names: "Bob" -> &str
names: "Frank" -> &str
names: "Ferris" -> &str
Upvotes: 1