Len must be known at compile time & 'let'

HI All,
I'm new to rust and enjoying it so far, just trying to get a handle on some things like this...

This method compiles and works fine:

fn make_ay(word: &str) -> String {
    let s = format!("{}-{}ay ",&word[1..word.len()], &word[0..1]);
    s
}

but, if I remove the 'let' and try to return the formatted string, whatever I try complains that the length isn't known at compile time. Adding the 'let' fixes it.
Does this have something to do with the stack vs heap? Does the method without the 'let' try to use the stack and therefore needs to know the length? Or, have I completely misunderstood?
Either way, I'm trying to understand why 'let' is the only way i can make this work rather than just accepting that it does :slight_smile:

I’m having a hard time reproducing your problem, as for example this compiles just fine:

fn make_ay(word: &str) -> String {
    format!("{}-{}ay ", &word[1..word.len()], &word[0..1])
}

Upon further trying around, I’m getting errors akin to the one you described if the & for the word slices are removed, e.g. format!("{}-{}ay ", word[1..word.len()], word[0..1]). That problem however occurs independent of whether let is used or not.

2 Likes

Thank you, if I try the function as you have it, I get the message "expected struct 'String', found ()"

If I change the return type to 'str' then I get the message, "doesn't have a size known at compile-time".

I've tried to retrace my steps to get the exact same code and error, however, I'm just finding that I had several problems and I've learned a lot today by trying to find a solution. So maybe my problem isn't related to 'let', but to various factors.
Maybe because this function cannot know the exact string length at compile time, I have to use 'string' and not 'str' anyway?

Don't put a semicolon after the format! call.

1 Like

You mean this error message?

error[E0308]: mismatched types
 --> src/lib.rs:1:27
  |
1 | fn make_ay(word: &str) -> String {
  |    -------                ^^^^^^ expected struct `String`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     format!("{}-{}ay ", &word[1..word.len()], &word[0..1]);
  |                                                           - help: consider removing this semicolon

Try to pay attention to any help that the compiler is trying to give you.

2 Likes

Yes, unlike other compilers you may be used to rustc works hard to give you useful information when you write something erroneous. You might have to break the habit of ignoring screens full of gcc spew :)

aha, yes, I read the first part but didn't read right to the end to find that really useful bit of info! You're right, other languages / compilers usually just give a lot of nonsense. Rust is refreshing is soooo many ways, the documentation is far better than any other language out there!
I mostly code in c# so have to deal with microsoft 'documentation' which is, well, is there a word for it?

As a rule of thumb, think about the str type as not existing on its own. You will usually only see and use &str instead. In Rust you usually encounter either

  • String, an “owned” heap-based string type, or perhaps mutable references to it &mut String
    • using an immutable reference &String for e.g. function parameters is considered an anti-pattern, use &str instead. If you ever have a &String, you can still pass it as &String can automatically be converted into &str
  • &str, a string slice, i.e. an immutable reference into some other String, or a string literal
    • slice means that &str can be referencing just part of a string. The internal representation of a &str consists of a pointer and a length
    • mentioning literals, the literal expressions like "hello world" themselves already have &str type, so you won’t need to put any additional &, e.g. &"hello world".

The format! macro itself does return a String which is then owned by the make_ay function (either assigned if you bind it so something with let, or living in an implicit local temporary variable). Thus your return type must be String, too; it can’t be str since that type doesn’t really exist on its own, and it can’t be a reference, e.g. &str since you cannot return references to local variables from a function.

1 Like

Thank you for the explanation, very much appreciated ! :slight_smile: