[Question]: E0515 - cannot return value referencing temporary value

Hello.
I have this method and the compiler hates it:

    pub fn gettype(&self) -> &str {
        match &self.value {
            Value::NullType                => "Null",
            Value::IntType(_)              => "Int",
            Value::FloatType(_)            => "Float",
            Value::StrType(_)              => "String",
            Value::BoolType(_)             => "Bool",
            Value::ArrayType(_, arraytype) => format!("Array<{}>", arraytype).as_str()
        }
    }

It complains about the format! statement returning a value referencing data owned by the current function. How can I fix this?

format! builds a new String from its arguments. You can’t return an &str reference to it because the data will be deallocated when the function exits. If you’re returning anything other than literals, you’ll need your function to return String instead of &str.

1 Like

It worked but now a have about 100 bugs to fix caused by that.
Thank you.

EDIT: Nevermind. That didn't create a single bug. I 'm not sure how.

Both String and &str implement Deref<Target=str>, which provides most of the useful read-only methods.

Note that by returning a String, you'll heap-allocate copies of your hard-coded string literals, which can be a pity.

  • A good general solution to mix &'static strs and Strings is to thus use an enum to support both cases, and then have convenience methods on the enum.

    And the good news is, that that enum already exists in the standard library: holy Cow!

    pub fn gettype(&self) -> Cow<'static, str>
                       // -> &'static str or String
    {
        match &self.value {
            Value::NullType                => "Null".into(),
            Value::IntType(_)              => "Int".into(),
            Value::FloatType(_)            => "Float".into(),
            Value::StrType(_)              => "String".into(),
            Value::BoolType(_)             => "Bool".into(),
            Value::ArrayType(_, arraytype) => format!("Array<{}>", arraytype).into(),
        }
    }
    

That being said, some people may stumble upon this thread with more complex types than &str and String, and so there may not be such a convenient enum available to them.

In which case, the more general solution is to use:

#[with]

  • Example:

    #[with('local)]
    pub fn gettype(&self) -> &'local str {
        match &self.value {
            Value::NullType                => "Null",
            Value::IntType(_)              => "Int",
            Value::FloatType(_)            => "Float",
            Value::StrType(_)              => "String",
            Value::BoolType(_)             => "Bool",
            Value::ArrayType(_, arraytype) => format!("Array<{}>", arraytype).as_str()
        }
    }
    

    And it Just Works™

That crate hasn't been yet fully released to the community yet, since I have yet to to release a guide / book for the crate to explain the motivation behind its design, and showcase some pretty neat usages we can do with it; but in the meantime it already works quite well.