3
votes

I'm a newbie in Rust and I'm still struggling with lifetimes in Rust. Below is an example from a book I'm reading. Could anyone help explain why the author can get this information just by looking at the function signature? I already have basic understanding of borrowing, references etc. but still can't understand it.

For example, suppose we have a parsing function that takes a slice of bytes, and returns a structure holding the results of the parse:

fn parse_record<'i>(input: &'i [u8]) -> Record<'i> { ... }

Without looking into the definition of the Record type at all, we can tell that, if we receive a Record from parse_record, whatever references it contains must point into the input buffer we passed in, and nowhere else (except perhaps at 'static values).

2
I am not sure, hence I comment, but this information can be probably derived from explicit lifetime 'i. Since Rust disallows returning reference to a local variable AND Record has the same lifetime as input it must mean that whatever is in the Record must come from input. - GrayCat
Think of a lifetime as a scope; the value with said lifetime will be dropped at the end of the scope. Therefore if we say that Record should live as long as the value in a scope we name 'i, we get Record<'i>. - Optimistic Peach

2 Answers

4
votes

The Record can get references only from the function body. In theory, these can come from

  • values in input, which are all references with lifetime 'i
  • values defined outside parse_record, which must have 'static lifetime
  • values defined in parse_record. These can be
    • dynamically created. Such values would be dropped by the end of the function scope, so any references to them would end up as dangling pointers. As such, this isn't allowed by the compiler.
    • literals (1, "cat"). These are actually baked into the binary, and so are effectively defined outside the function. In the function they're 'static references
2
votes

The input:

input: &'i [u8]

Says the following:

I am a reference to a series of bytes ([u8]) that will live for at least as long as 'i.

So, when saying that I've a type that looks like this: Record<'i>, I can say the following about it:

I am a struct (Named Record<'i>) that contains something (Perhaps a reference, perhaps something else) that depends on something living for at least as long as 'i.

What lifetimes on references/structs/enums/whatever are telling you is that there is a dependency that an object that lives in 'i must live as long as I do.

In other words, this function signature tells you that the Record must live as long as the bytes referenced by input (The u8s under the reference, not the reference itself).


A lack of a lifetime parameter was recently deprecated and now causes a warning, so keep in mind when reading examples like the following:

fn parse_record(input: &[u8]) -> Record

that there may be a lifetime attached to Record so you must consult some kind of documentation. The compile desugars this (And the warning asks you to do this yourself) to this:

fn parse_record(input: &'_ [u8]) -> Record<'_>

This is identical to your 'i example.