Issue with printing ‍`char`s

Hello,
I'm learning rust with The Book, in the end of chapter 8.3 of the book, there's some suggested projects to build, I was doing the Latin Pig project, but I came across following error,


error[E0277]: the size for values of type `[char]` cannot be known at compilation time
  --> src/main.rs:21:32
   |
21 |         format!("{:?}-{:?}ay", characters[1..], characters[0])
   |                  ----          ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |                  |
   |                  required by this formatting parameter
   |
   = help: the trait `Sized` is not implemented for `[char]`
   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `pig_latin` (bin "pig_latin") due to 1 previous error

Here's my code (happy to hear if my way wasn't correct and my above question was kinda an xy problem because how I managed to make a vector of characters wasn't a good way of implementing the problem.)

fn main() {
    let word1 = "first";
    let word2 = "apple";
    println!("{} {}", pig_latin(word1), pig_latin(word2));
}

fn pig_latin(word: &str) -> String {
    let vowels = ['a', 'e', 'u', 'i', 'o'];
    let mut characters = Vec::new();
    for character in word.chars() {
        characters.push(character);
    }
    let is_first_letter_vowel = if vowels.contains(&characters[0]) {
        true
    } else {
        false
    };
    let result = if is_first_letter_vowel {
        format!("{word}-hay")
    } else {
        format!("{:?}-{:?}ay", characters[1..], characters[0])
    };
    result
}

Thanks!

You need a & right here:

format!("{:?}-{:?}ay", &characters[1..], characters[0])
                       ^

That creates a fat pointer that includes the size of the slice. For details, see the reference docs:

3 Likes

It's too bad that the compiler doesn't suggest to add the &. My guess is this is too deep in macro / internals land for it to trigger the suggestion?

For example, adding an intermediate function, it catches on and adds a suggested fix:

1 Like

Under the hood, format! and friends take references to their value arguments; they don't try to pass them elsewhere by value. Add references to your format_it calls in your playground and you'll see the ?Sized error again (it's an issue with the implicit generic bounds). Or here's minification.

I believe these are the actual functions involved. (The format machinery does various type-erasing pointer tricks that probably require the Sized bound.) Those are private and foreign, which inhibits the note (and signature change suggestion), but there's no "add (another) &" suggestion being dropped.

So I think this is more a signature based shortcoming than a macro based one.

Anyway, whatever the reason, I agree it'd be a worthy improvement to suggest adding & when it would make the bounds be satisfied.

3 Likes

Thanks for your help!