1

I am a beginner in rust, following rust-lang/book.
In it's ch10.3. Validating References with Lifetimes there is a Listing 10-20:

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest(x: &str, y: &str) -> &str {  // <-- ERROR
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

There are two points they have mentioned :

  • Rust can’t tell whether the reference being returned refers to x or y. // <-- no need, according to me
  • We also don’t know the concrete lifetimes of the references that will be passed in, to determine whether the reference we return will always be valid.

In the code below, their is no error (as expected) :

fn main() {
    let string1 = String::from("abcd")  ;
    let string2 = "xyz";

    let x: &str = &string1.as_str();
    let y: &str = &string2;


    let result =    
    if x.len() > y.len() {
        x
    } else {
        y
    };

    println!("The longest string is {}", result);
}

Confusion :

Why Rust need to tell whether the reference being returned refers to x or y ?
Silly question, but I want to know...

Edited

Solution :

Suppose that function call is call by customer, and function as the seller

In snippet one,
Then, function call expect that it will get one of the value, passed in argument, in return (as in snippet one)
But, if seller is biased or accidently give value other than parameters. like -

fn longest(x: &str, y: &str) -> &str {
    let z = "Other String";
    &z
}

Then, both function call and function both will get error message
But, their is no any mistake of customer.
Therefore, Rust ensure that customer will not get any error, for the mistake of seller, with the help of annotating lifetime parameter.

This is also the reason of, "Why Typescript introduced in Javascript".

In snippet two,
Both customer and seller is the same function

The related question, mentioned below
Why are explicit lifetimes needed in Rust?

2 Answers2

0

In the second snippet, the lifetime used is the shorter of x and y.

But Rust does not do lifetime inference (or any inference at all) across function boundaries. It always requires you to specify explicitly the types and lifetimes involved. Thus, the lifetime that was inferred in the second snippet needs to be specified explicitly in the first.

The most important reason for that is to avoid unintentional breakage. If functions' type would be inferred it would be too easy to break APIs accidentally. Thus Rust by design requires you to specify signatures explicitly.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • Thanks for answering! You answer make me think again over my question, which lead me to [this](https://doc.rust-lang.org/nomicon/lifetimes.html) page. But the answers to the question (mentioned in edit 1 of this question) satisfy me – Mohit Saini Sep 08 '22 at 10:28
  • Please take a look at **Edited Question**, And let me know if I'm right. – Mohit Saini Sep 08 '22 at 15:05
0

First Case

Suppose that Rust didn't give an error with your definition of longest(). Then it's possible to use longest() such that the returned address is stored in a variable that has a longer lifetime than the string slices passed in. For example, something like this:

    let result: &str;
    {
        let x = String::from("welcome");
        let y = String::from("bye");

        result = longest(&x, &y);
    } // `x` and `y` go out of scope, so `&x` and `&y` are no longer valid.

    // This would be undefined behavior, because the data pointed to
    // by `result` is no longer valid.
    println!("result: {}", result);

Since result is used after x and y go out of scope, and result points to the data in either x or y, this would lead to undefined behavior. But Rust doesn't allow this; instead, the Rust compiler forces you to make the returned value of longest() has a sufficiently long lifetime.

So if the compiler didn't give an error with how you wrote longest(), then yes in your example there wouldn't be undefined behavior (because x, y, and result all have the same lifetime), but in general certain invocations of longest() and variables subsequently going out of scope could lead to undefined behavior. So to prevent this, Rust forces you to annotate the lifetimes to make sure the returned address has a long enough lifetime.

Second Case

The variables x, y, and result are all cleaned up at the same time when they go out of scope. So the address referenced by result is always valid whether it's the address of x or the address of y. So there's no error.

Andrew
  • 904
  • 5
  • 17
  • Thanks for answering! The **code you mentioned will not work** even if we add explicit annotation is in it. The problem in the code itself (Dangling References Problem). Let me know, if there is some misunderstanding. – Mohit Saini Sep 08 '22 at 10:28
  • Please take a look at **Edited Question**, And let me know if I'm right. – Mohit Saini Sep 08 '22 at 15:05