Saltar al contenido principal
eLearner.app
Módulo 6 · Lección 2 de 212/14 en el curso~15 min
Lecciones del módulo (2/2)

Smart Pointers: Box y Rc

Un smart pointer (puntero inteligente) es una estructura de datos que se comporta como un puntero, pero posee metadatos y funcionalidades adicionales (como el recuento de referencias o la gestión automática de la memoria).

En Rust, las referencias ordinarias (como &) solo toman prestados datos. Los smart pointers, por el contrario, a menudo poseen los datos a los que apuntan. Eemplos comunes incluyen String y Vec<T>, pero la biblioteca estándar proporciona otros especializados.


Box<T> para asignar en el Heap

El smart pointer más simple es Box<T>, que almacena los datos en el heap en lugar de en la pila. En la pila solo queda el puntero al dato asignado en el heap.

Se usa principalmente en los siguientes casos:

  1. Cuando se tiene un tipo cuya dimensión no puede ser conocida en el momento de la compilación (como un tipo recursivo), y se quiere utilizar un valor de ese tipo en un contexto que requiere una dimensión exacta.
  2. Cuando se quieren transferir datos de gran tamaño sin copiarlos.

Ejemplo básico:

Code
fn main() {
    let b = Box::new(5); // alloca il valore 5 nello heap
    println!("b = {}", *b); // de-referenzia con * per leggere il valore
}

Tipos Recursivos y Cons List

Un tipo recursivo es un tipo que puede contener un valor de sí mismo en su interior. Rust debe conocer la dimensión exacta de un tipo en tiempo de compilación. Dado que la profundidad de un tipo recursivo podría ser infinita, el compilador genera un error a menos que se utilice un Box (que tiene una dimensión fija, ya que es un puntero):

Code
enum List {
    Cons(i32, Box<List>),
    Nil,
}

Rc<T>: Recuento de Referencias (Reference Counting)

Hay casos en los que un solo valor puede tener múltiples propietarios. El smart pointer Rc<T> (Reference Counted) realiza un seguimiento del número de referencias a un valor para determinar si el valor sigue en uso. Si el recuento llega a cero, el recurso se desasigna de forma segura.

[!NOTE] Rc<T> se puede utilizar exclusivamente en escenarios de un solo hilo (single-thread). Para escenarios de múltiples hilos (concurrentes) se debe utilizar Arc<T> (Atomic Reference Counted).

Code
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a); // incrementa il contatore a 2
    println!("Riferimenti: {}", Rc::strong_count(&a));
}

Pruébalo tú

Ejercicio 1: Asignar con Box

Ejercicio#rust.m6.l2.e1
Intentos: 0Cargando...

Asigna un valor entero igual a 42 en el heap utilizando Box::new y asígnalo a una variable llamada val. Luego, imprime en pantalla el valor almacenado en el Box desreferenciándolo explícitamente con el operador *.

Cargando editor...
Mostrar pista

Usa `let val = Box::new(42);` para almacenar el valor en el heap y desreferéncialo con `*val` dentro de `println!`.

Solución disponible después de 3 intentos

Ejercicio 2: Estructura de datos recursiva (Cons List)

Ejercicio#rust.m6.l2.e2
Intentos: 0Cargando...

Define un enum recursivo llamado List que contenga dos variantes: Cons, que encierra una tupla (i32, Box<List>), y Nil, que representa el final de la lista. En el main, instancia una lista enlazada que contenga el elemento 1 seguido de Nil.

Cargando editor...
Mostrar pista

El enum se declara como `enum List { Cons(i32, Box<List>), Nil }`. Instancia la lista con `List::Cons(1, Box::new(List::Nil))`.

Solución disponible después de 3 intentos

Ejercicio 3: Compartir la propiedad con Rc

Ejercicio#rust.m6.l2.e3
Intentos: 0Cargando...

Usa std::rc::Rc para crear un entero compartido que contenga el valor 100 dentro de una variable a. Clona la referencia en una variable b usando Rc::clone. Por último, imprime en pantalla el contador de referencias activas usando la función Rc::strong_count.

Cargando editor...
Mostrar pista

Crea el valor con `Rc::new(100)`. Clona con `Rc::clone(&a)`y muestra el recuento de propietarios con`Rc::strong_count(&a)`.

Solución disponible después de 3 intentos