简体   繁体   中英

Rust lifetime inference for struct methods

This code is based on the example code in the Rust book in the lifetimes chapter. I was wondering how do the following two versions of the same method differ:

struct Important<'a> {
    part: &'a str,
}

impl<'a> Important<'a> {
    fn larger<'b>(&'b self, other: &'b str) -> &'b str {
        if self.part.len() > other.len() {
            self.part
        } else {
            other
        }
    }
}

versus

struct Important<'a> {
    part: &'a str,
}

impl<'a> Important<'a> {
    fn larger(&self, other: &'a str) -> &str {
        if self.part.len() > other.len() {
            self.part
        } else {
            other
        }
    }
}

I guess in the first version we are instructing the compiler that

  1. Find a lifetime 'b such that both &self and the reference other are valid during it (probably the shorter of the two lifetimes if they overlap)

  2. Make sure that the returned reference is only used within that lifetime 'b because outside it might become a dangling reference.

What does the second version of the code do? One of the lifetime elision rules in the Rust book says that in a struct method the returned reference is assigned the lifetime of the &self parameter (which is 'a here), so are we saying that other should also be valid for the same lifetime as the &self parameter, which is the lifetime 'a ?

Semantically, is this the same code or could these versions behave differently depending of the lifetimes of other and the struct?

What does the second version of the code do? One of the lifetime elision rules in the rust book says that in a struct method the returned reference is assigned the lifetime of the &self parameter (which is 'a here), so are we saying that other should also be valid for the same lifetime as the &self parameter, which is the lifetime 'a ?

That's slightly inaccurate, the lifetime of &self in the second example is not 'a but it is bounded by 'a . The second example would desugar to this if we expand it by reversing Rust's lifetime elision rules:

struct Important<'a> {
    part: &'a str,
}

impl<'a> Important<'a> {
    fn larger<'b>(self: &'b Important<'a>, other: &'a str) -> &'b str {
        if self.part.len() > other.len() {
            self.part
        } else {
            other
        }
    }
}

The reason why self is bounded by 'a is because &'b Important<'a> implies 'b: 'a or in plain terms " 'a outlives 'b " which must be true otherwise the reference may get invalidated. If we expand the first example the type of self again becomes &'b Important<'a> . The only difference between the first and second example is the type of other , in the first it's &'b str and in the second it's &'a str but that's an irrelevant detail since the return value has the type &'b str which is constrained by the 'b lifetime and we know that 'b: 'a so functionally both examples are the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM