ProgramaciónDesarrollador backend de Rust

Explique cómo funciona el trabajo con estructuras de datos inmutables (immutable) y mutables (mutable) en Rust, y cuándo es necesaria la mutabilidad. ¿Cuáles son las limitaciones prácticas asociadas con esto, y cómo se pueden evitar de manera adecuada?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

En Rust, las estructuras de datos son inmutables por defecto. Esto significa que cualquier variable o referencia declarada sin la palabra clave mut no puede ser cambiada después de la inicialización.

let mut value = 10; // variable mutable value += 5; let value2 = 10; // variable inmutable // value2 += 5; // error de compilación: cannot assign twice to immutable variable

La misma lógica se aplica a los campos de las estructuras:

struct Point { x: i32, y: i32 } let mut pt = Point { x: 1, y: 2 }; pt.x = 5; // OK, ya que pt está declarado como mut

Sin embargo, la mutabilidad solo afecta el "nivel superior" de la variable: si la estructura se almacena detrás de una referencia inmutable, sus datos no se pueden cambiar, incluso si se declaran como mut dentro de la estructura.

Otra forma de sortear las limitaciones es utilizar tipos especiales como RefCell<T> o contenedores atómicos. Esto permite modificar datos dentro de contenedores que parecen inmutables mediante “mutabilidad interna” (interior mutability), por ejemplo:

use std::cell::RefCell; struct Counter { count: RefCell<i32>, } let counter = Counter { count: RefCell::new(0) }; *counter.count.borrow_mut() += 1; // seguro, a pesar de la ausencia de mut

Pregunta trampa.

Pregunta: ¿Se puede cambiar el valor de un campo de la estructura si la variable misma no está declarada como mut, pero el campo está explícitamente declarado como mut en la propia estructura?

Respuesta incorrecta típica: Sí, si el campo está declarado como mut, se puede cambiar.

Respuesta correcta: La palabra clave mut no puede ser utilizada al declarar un campo de estructura. La mutabilidad se refiere solo a la propia variable o a la referencia obtenida. Para modificar un campo de una estructura, es necesario declarar la variable como mut, o utilizar tipos de “mutabilidad interna” (por ejemplo, RefCell).

Ejemplo:

struct Foo { val: i32 } // campo declarado sin mut let mut foo = Foo { val: 1 }; foo.val = 2; // OK let foo2 = Foo { val: 3 }; foo2.val = 4; // ¡error! la variable no es mutable

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

En un gran proyecto, uno de los desarrolladores intentó cambiar un campo de la estructura, pensando que declarar el campo como mut ("struct S { mut x: i32 }") le daría la mutabilidad necesaria. Esto no pudo compilar, y el proceso de refactorización se extendió por varias horas, hasta que se le explicó que la mutabilidad es una característica de la propiedad de la variable, no de la estructura.


Historia

En un proyecto relacionado con la multithreading, toda la lógica de control de acceso a los datos se mantuvo en una estructura estática global. Sin conocer las posibilidades de "mutabilidad interna" a través de RefCell, el equipo escribió mecanismos de bloqueo y carreras excesivamente complejos, en lugar de una solución simple a través de Arc<Mutex<T>> o RwLock<T>.


Historia

Un desarrollador olvidó declarar el argumento de la función como mut dentro de la firma, y la función no pudo cambiar la estructura pasada, por lo que el bug solo se manifestó en producción (los datos no se actualizaban después de llamar a la función). Saber que por defecto el paso se realiza por una referencia inmutable le habría permitido evitar errores en las primeras etapas.