Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do slices in a structure require a lifetime, but not vectors?

Tags:

rust

When I define the following structure:

struct Test<'a> {
    a: &'a [i64],
    b: Vec<i64>,
}

Both the slice and the vector contain a pointer. Why does the slice require a lifetime, but not the vector?

like image 359
tbicr Avatar asked Oct 14 '14 22:10

tbicr


1 Answers

A vector owns its elements. That means the vector is responsible for allocating and freeing the elements it points to. The lifetime of the vector's elements is the same as the lifetime of the vector itself, so there's no need to specify a lifetime to the Vec type.

A slice borrows the elements of a vector or array that may be allocated statically or dynamically. The slice must indicate the lifetime of the borrowed elements so that the compiler can make the necessary safety checks.

Another way to express this is by comparing the sequence of events between the two options.

For a vector:

  1. A Vec is allocated. No storage is allocated for the elements initially (when the Vec is empty).
  2. As elements are added to the vector, storage for the elements is allocated from the heap. The Vec stores a pointer to that storage.
  3. When the vector is dropped, the storage for the elements is first freed, then the Vec itself is freed.

For a slice:

  1. Some storage is allocated for an array or a vector of elements, either statically or dynamically.
  2. A slice is allocated and initialized to reference some or all of the elements of this storage. The slice stores a pointer to the first element.
  3. When the slice is dropped, the storage for the elements is not freed, because the slice doesn't own it; only the slice is dropped.
  4. If the storage was allocated dynamically, it will eventually be freed.

EDIT

Generally speaking, a lifetime annotation is required on borrowed pointers (&'a X), on types that contain borrowed pointers (X<'a>, where X is a struct or enum that has a member that is a borrowed pointer) and on trait objects/constraints (X+'a, where X is a trait) when those types are used as members of a struct or enum.

On let bindings and on the right-hand side of the as operator, you usually write borrowed pointer types without a lifetime annotation (i.e. just &X), because the compiler infers the lifetime in that case.

What you need to remember is that lifetime annotations are necessary when dealing with borrowed pointers, either directly or indirectly.

If you want to learn more about ownership, borrowing and lifetimes, I suggest you read the Rust Guide's section on pointers as well as the Rust References and Lifetimes Guide

like image 131
Francis Gagné Avatar answered Oct 19 '22 19:10

Francis Gagné