Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do rust lifetimes only refer to references?

Tags:

rust

I'm trying to wrap my head around Rust lifetimes (as the official guides don't really explain them that well).

Do rust lifetimes only refer to references, or can they refer to base/primitive values as well?

like image 371
Qix - MONICA WAS MISTREATED Avatar asked Dec 15 '14 03:12

Qix - MONICA WAS MISTREATED


3 Answers

Lifetimes are the link between values and references to said values.

In order to understand this link, I will use a broken parallel: houses and addresses.

A house is a physical entity. It is built on a piece of land at some time, will live for a few dozen or hundred years, may be renovated multiple times during this time, and will most likely be destroyed at some point.

An address is a logical entity, it may point to a house, or to other physical entities (a field, a school, a train station, a company's HQ, ...).


The lifetime of a house is relatively clear: it represents the duration during which a house is usable, from the moment it is built to the moment it is destroyed. The house may undergo several renovations during this time, and what used to be a simple cabana may end up being a full-fledged manor, but that is of no concern to us; for our purpose the house is living throughout those transformations. Only its creation and ultimate destruction matter... even though it might be better if no one happen to be in the bedroom when we tear the roof down.

Now, imagine that you are a real estate agent. You do not keep the houses you sell in your office, it's impractical; you do, however, keep their addresses!

Without the notion of lifetime, from time to time your customers will complain because the address you sent them to... was the address of a garbage dump, and not at all that lovely two-story house you had the photography of. You might also get a couple of inquiries from the police station asking why people holding onto a booklet from your office were found in a just destroyed house, the ensuing lawsuit might shut down your business.

This is obviously a risk to your business, and therefore you should seek a better solution. What if each address could be tagged with the lifetime of the house it refers to, so that you know not to send people to their death (or disappointment) ?


You may have recognized the C manual memory management strategy in that garbage dump; in C it's up to you, the real estate agent developer, to make sure that your addresses (pointers/references) always refer to living houses.

In Rust, however, the references are tagged with a special marker: 'enough; it represents the a lower-bound on the lifetime of the value referred.

When the compiler checks whether your usage of the reference is safe or not, it asks the question:

Is the value still alive ?

It does not matter whether the value will be there for a 100 years afterward, as long as it lives long 'enough for the use you have of it.

like image 125
Matthieu M. Avatar answered Oct 16 '22 03:10

Matthieu M.


No, they refer to values as well. If it is not clear from the context how long they will live, they have to be annotated as well. It is then called a lifetime bound.

In the following example it is necessary to specify that the value, the reference is referring to, lives at least as long as the reference itself:

use std::num::Primitive;

struct Foo<'a, T: Primitive + 'a> {
    a: &'a T
}

Try deleting the + 'a and the compiler will complain. This is required since T could be anything implementing Primitive.

like image 45
Ferio Avatar answered Oct 16 '22 02:10

Ferio


Yes, they only refer to references, however those references can refer to primitive types. Rust is not like Java (and similar languages) that make a distinction between primitive types, which are passed by value, and more complex types (Objects in Java) that are passed by reference. Complex types can be allocated on the stack and passed by value, and references can be taken to primitive types.

For example, here is a function that takes two references to i32's, and returns a reference to the larger one:

fn bigger<'a>(a: &'a i32, b: &'a i32) -> &'a i32 {
    if a > b { a } else { b }
}

It uses the lifetime 'a to communicate that the lifetime of the returned reference is the same as that of the references passed in.

like image 21
wingedsubmariner Avatar answered Oct 16 '22 02:10

wingedsubmariner