Search code examples
rustcompilationsizecompile-time

Rust error : doesn't have a size known at compile-time


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.


Solution

  • 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