1

I am trying to write a method of an object that returns a combination of String fields of that object. I have tried several approaches, as you can see in the example code, and in each case I am getting errors shown below including

  • expected &str, found struct std::string::String
  • s is borrowed here
  • cannot return value referencing local variable s
struct Person {
    first_name: String,
    last_name: String,
    age: u8,
}
// BEHAVIOR OF CLASS
impl Person {
    fn full_name(&self) -> &str {
        let s = format!("{} {}", self.first_name, self.last_name);

        // temporary, test
        println!("** test, s: {}", s);

        // how to return the 's' value?

        // try 1. expected `&str`, found struct `std::string::String`
        // s
        // try 2. `s` is borrowed here
        // s.as_str()
        // try 3. cannot return value referencing local variable `s`
        // &s[..]
        // try 4. cannot return value referencing local variable `s`
        // &*s

        // then escape
        "?"
    }

    // works fine
    fn description(&self) -> &str {
        match self.age {
            0..=12 => "Clild",
            13..=17 => "Teenager",
            _ => "Adult",
        }
    }
}

fn main() {
    println!("Laboratory");

    let p = Person {
        first_name: String::from("Alexandra"),
        last_name: String::from("Ansley"),
        age: 25,
    };

    println!("Full Name   : {}", p.full_name());
    println!("Description : {}", p.description());
}

How can I write this method without these errors?

2
  • 4
    What you try to do is a classic dangling pointer mistake, and Rust rightfully prevents you from doing it. You create a String object, and try to return a reference to it. But, the String object will be destroyed immediately after the function ends. You better return the object itself, not a reference. Return String type, and return it as just s Commented Nov 15, 2021 at 7:18
  • 1
    An answer that took me 2 hours to skate. But I wasted no time and learned my lesson. -> String ... TXS Commented Nov 15, 2021 at 8:36

2 Answers 2

1

Explanation for Trial 1:

fn full_name(&self) -> &str {
        // format macro returns a String
        let s = format!("{} {}", self.first_name, self.last_name);        
        s // Error: return type and given type doesn't match 
    }

Explanation for Trial 2:

fn full_name(&self) -> &str {
        let s = format!("{} {}", self.first_name, self.last_name); // owned value     
        let s_str = s.as_str() // reference to s

        s_str
    } // s is dropped here

// s_str is now a dangling pointer, so it is rightly refused by the borrow checker

Explanation for Trial 3:

fn full_name(&self) -> &str {
        let s = format!("{} {}", self.first_name, self.last_name); // owned value     
        let s_str = &s[...] // is equivalent to s.as_str()

        s_str // reference to s
    } // s is dropped here

// s_str is now a dangling pointer, so it is rightly refused by the borrow checker

Explanation for Trial 4:

impl Person {
    fn full_name(&self) -> String {
        let s = format!("{} {}", self.first_name, self.last_name);
        
        let s_str = &*s // is equivalent to &*std::ops::Deref(&s), which is of type &str 
        // see https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-dereference-operator

        s_str  // reference to s 
    }  // s is dropped here
}

// s_str is now a dangling pointer, so it is rightly refused by the borrow checker

You need to return a String instead of &str since:

  • You can't return reference to an owned value created inside a function definition block without creating a dangling pointer.
  • and you can't concatenate two &str together without allocating both of them into a String, because &str needs to be contiguous memory (see docs)
Sign up to request clarification or add additional context in comments.

Comments

0

(Given your comments, I think you already know everything here. I'm just writing for later searchers.)

fn full_name(&self) -> &str { ... }

The most important fact about this signature is that it must return a reference to existing memory. It can't create any new thing. The whole point of &str is "a pointer to something that will exist for at least as long as you have this reference."

So this would be fine if there were a property on this struct that held onto full_name. But if the function constructs "the full name," this is impossible.

The most natural thing to do here is return String (and that's my recommendation). That's an owned value, so you can create it in the function and transfer it to the caller.

Another approach would be to have a full_name property that started empty, and was lazily filled in when requested and returned as a &str, with the promise that it would live as long as the struct.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.