Estática

Rust tiene algunos nombres reservados de vida útil. Uno de ellos es static. Puedes encontrarlo en dos situaciones:

// Una referencia con vida útil 'static:
let s: &'static str = "hola mundo";

// 'static como parte de un vínculo de rasgo
fn generico<T>(x: T) where T: 'static {}

Ambos están relacionados pero son sutilmente diferentes y esta es una fuente común de confusión al aprender Rust. A continuación, se muestran algunos ejemplos para cada situación:

Vida útil de referencia

Como vida útil de referencia, 'static indica que los datos apuntados por la referencia duran toda la vida útil del programa en ejecución. Todavía se puede obligar a una vida útil más corta.

Hay dos formas de crear una variable con una vida útil 'static, y ambas se almacenan en la memoria de solo lectura del binario:

  • Hacer una constante con la declaración static.
  • Hacer un literal string que tenga el tipo: &'static str

Consulta el siguiente ejemplo para ver una visualización de cada método:

// Hace una constante con vida útil `'static`.
static NUM: i32 = 18;

// Devuelve una referencia a `NUM` donde su vida útil `'static` es obligada por el 
// argumento de entrada.
fn obliga_static<'a>(_: &'a i32) -> &'a i32 {
    &NUM
}

fn main() {
    {
        // Hace un literal `string` e imprímelo:
        let cadena_estatica = "Estoy en la memoria de solo lectura";
        println!("cadena_estatica: {}", cadena_estatica);

        // Cuando `cadena_estatica` sale del alcance, la referencia ya no se puede usar,
        // pero los datos permanecen en el binario.
    }

    {
        // Hace un número entero para usarlo con `obliga_static`:
        let numero_vida_util = 9;

        // Obliga `NUM` a la vida útil de `numero_vida_util`:
        let estatico_obligado = obliga_static(&numero_vida_util);

        println!("estatico_obligado: {}", estatico_obligado);
    }

    println!("NUM: {} se mantiene accesible!", NUM);
}

Vínculo de rasgo

Como vínculo de rasgo, significa que el tipo no contiene referencias no estáticas. Por ejemplo el receptor puede retener el tipo durante el tiempo que quiera y nunca dejará de ser válido hasta que lo suelte.

Es importante entender que esto significa que cualquier dato de propiedad siempre pasa un límite de vida 'static, pero una referencia a esos datos de propiedad generalmente no:

use std::fmt::Debug;

fn imprimelo( entrada: impl Debug + 'static ) {
    println!( "valor 'static pasado es: {:?}", entrada );
}

fn main() {
    // i es propio y no contiene referencias, por lo que es 'static:
    let i = 5;
    imprimelo(i);

    // Vaya, &i solo tiene el tiempo de vida definido por el alcance de main(), por lo
    // que no es 'static:
    imprimelo(&i);
}

El compilador te dirá:

error[E0597]: `i` does not live long enough
  --> src/lib.rs:15:15
   |
15 |     imprimelo(&i);
   |     ---------^^--
   |     |         |
   |     |         borrowed value does not live long enough
   |     argument requires that `i` is borrowed for `'static`
16 | }
   | - `i` dropped here while still borrowed

Ve también

constantes 'static