La pila, la memoria dinámica y los punteros
La pila ("stack" en inglés), la memoria dinámica ("heap" en inglés) y los punteros son elementos muy importantes en Rust.
La pila y la memoria dinámica son dos tipos de almacenamiento de los datos de un programa durante su ejecución. Sus diferencias más importantes son:
- La pila es muy rápida, la memoria dinámica no lo es tanto. Tampoco es lenta, pero siempre es más rápido acceder a la pila. Aunque no es posible utilizar la pila siempre porque:
- Rust necesita conocer el tamaño de una variable en durante su compilación para poder guardarla en la pila. Así, las variables simples como
i32
van a la pila ya que se conoce su tamaño exacto. Se sabe que va a ocupar 4 bytes, 32 bits = 4 bytes. Por lo tanto, los datos de tipoi32
pueden ir siempre a la pila. - Algunos tipos no tienen un tamaño conocido en tiempo de compilación. No pueden guardarse en la pila. ¿Qué se puede hacer? En primer lugar, se pone la información en la memoria dinámica ya que esta puede contener datos de cualquier tamaño. En segundo lugar, se guarda un puntero en la pila. El tamaño de los punteros es conocid. Así, para recuperar un valor de una variable que está en la memoria dinámica, el ordenador va primero a la pila, obtiene el puntero y lo sigue hasta la memoria dinámica para localizr el dato que se busca.
Los punteros parecen complicados, pero no lo son. Son como una tabla de contenidos de un libro. Imagina este libro:
MI LIBRO
TABLA DE CONTENIDO
Capítulo Página
Capítulo 1: mi vida 1
Capítulo 2: mi gato 15
Capítulo 3: mi trabajo 23
Capítulo 4: mi familia 30
Capítulo 5: mis planes futuros 43
La tabla de contenido es como una "pila" que, en este caso, contiene cinco punteros. Puedes leerlos y encontrar la información sobre la que tratan. ¿Dónde está el capítulo sobre "mi vida"? Está en la página 1 (Apunta a la página 1). ¿Dónde está el capítulo sobre "mi trabajo"? Está en la página 23.
El puntero que se ve habitualmente en Rust se denomina referencia. Esto es lo importante que se debe saber: una referencia apunta a la memoria de otro valor. Una referencia supone que se tome prestado el valor, pero no se apropia de él. Es lo mismo que en el libro anterior: la tabla de contenidos no posee la información. Se encuentra en los capítulos que son los que la poseen. En Rust, las referencias llevan el símbolo &
al principio de ellas. Así.
let mi_variable = 8
crea una variable normal, perolet mi_referencia = &mi_variable
crea una referencia. Se lee como "mi_referencia es una referencia a mi_variable" o como "mi_referencia se refiere a mi_variable".
Esto significa que mi_referencia
solo mira a los datos de mi_variable
. mi_variable
sigue siendo propietaria de sus datos.
También es posible tener una referencia que "apunte" a otra referencia. Hasta culquier número de referencias.
fn main() { let mi_numero = 15; // Esto es un i32 let referencia_simple = &mi_numero; // Esto es una &i32 let referencia_doble = &referencia_simple; // Esto es una &&i32 let referencia_quintuple = &&&&&mi_numero; // Esto es una &&&&&i32 }
Todos estos son tipos de dato diferentes, de la misma forma que "un amigo de un amigo" es diferente de "un amigo".