Rust lang series episode #12— lifetimes (#rust-series)

Words
535
Reading
3 min
Listen
Play
10y

Hello everyone, welcome to a new Rust programming episode. In episode #7 of this series we discussed ownership and borrowing. There is one more related topic and it's lifetimes. While speaking about lifetimes we are speaking about lifetimes of used resources living in memory.

Why to bother with lifetimes at all? Consider this scenario:

  • get resource
  • lend reference of that resource
  • dealocate resource
  • use the resource

This will be problem because you wish to use resource that is no more available. In some languages garbage collector is taking care of this, but there is a cost in performance and additional resources. In some other languages you need to take care of that but it's common source of bugs which are not easy to be found. In Rust, compiler will do the checks and force you to make it in safe way (unless you disable it with unsafe keyword - this will be discussed in future episodes).

Lifetime wanted

Check this example.

struct Project {
    name: &str
}

fn main() {
    let p = Project { name: "Steemit"};
}

# output
2:16 error: missing lifetime specifier [E0106]

Rust complains because it cannot assure that name will not be lost without Person. In some simple situations compiler can do this for us, this is called lifetime elision. But if not, the compiler complains and forces us to specify lifetime explicitly so there is no risk. Lifetime is specified similar to generics but with ' sign.

Lifetime definition

struct Project<'a> {
    name: &'a str
}

fn main() {
    let p = Project { name: "Steemit"};
    println!("{}", p.name);
}

# output
Steemit

We can read it like this. Struct Project is using lifetime with a and struct variable name has the same lifetime. It means struct cannot live longer than the named variable;

What if we want to implement some struct method. In such a case compiler will force us to use lifetimes as well.

impl<'a> Project<'a> {
  fn printProjectName(&self) {
    println!("Project name: {}", self.name);
  }
}

fn main() {
  let p = Project { name: "Steemit" };
  p.printProjectName();
}

# output
Project name: Steemit

You can try to remove lifetime definition from impl and you'll see that compiler will block you to work like that.

error: wrong number of lifetime parameters: expected 1, found 0 [E0107]

Multiple lifetimes

You can define multiple lifetimes. This can be used when you have. Check this example

static ZERO: i32 = 0;

fn get_zero_if_not_equal<'a, 'b>(first: &'a i32, second: &'b i32) -> &'a i32 {
    if first == second {
        return first
    } else {
        return &ZERO
    }
}

fn main() {
    let x = 1;
    let v;
    {
        let y = 2;
        v = get_zero_if_not_equal(&x, &y);
    }
    println!("{}", v);
}

# output
0

Note: static variables are sort of global variables that are not inlined and has fixed location in memory. Global variable that is inlined upon use can be defined with const.

Also note it's not necessary to derefernce a and b with * when comparing values in simple if-else statement (will be discussed more in the future) thanks to Rust auto-dereferencing.

You see, scopes of function input references has various scopes and therefore single lifetime cannot be used here. If we do it (you can try it yourself), we will receive this complain from compiler.

error: `y` does not live long enough

Static lifetime

You can define lifetime that will be valid through entire application life with 'static. Sometimes it's useful. It can simplify some definitions but you should limit lifetimes as much as possible.

let greetings: &'static str = "Hi Steemiters";

Uff, what a topic today, right? Don't worryif you don't feel to be master of Rust lifetimes yet. It will be better with more practice.

Postfix

That's all for today, thanks for all appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). Jesus bless your programming skills, use them wisely and see you during next episodes.

Meanwhile you can also check official documentation to find more about lifetimes:

#rust-series
#rust-lang
#rust