Aunque Rust proporciona su libro Rust, tuve dificultades para comprender la palabra clave mut
. Me pregunté: "¿Soy el único que tiene este problema?" Una búsqueda rápida en Google confirmó que no estaba solo.
Como resultado, decidí escribir este artículo para brindar una explicación detallada de la palabra clave mut
. Este artículo está destinado a quienes provienen de lenguajes de alto nivel como Python o JavaScript.
Para crear una variable inmutable en Rust, simplemente escriba let x = 1337
. Es sencillo. Si desea crear una variable que pueda modificarse más adelante, simplemente agregue la palabra clave mut
después de let
. Rust tiene una convención útil que fomenta la claridad de intenciones.
Agregar la palabra clave mut
informa a los demás que esta variable se modificará en otra parte del código. Bueno.
Visualicémoslo. Dos variables aquí, let mut x = 1337
y let y = 42
.
Por el momento todo es sencillo. Sin embargo, las cosas empiezan a ponerse un poco complicadas cuando se utilizan referencias mut
. Creemos algunos.
let mut x = 1337; let y = 42; let x_ref = &mut x; let y_ref = &y;
En el esquema dado, tengo 4 variables, 2 de las cuales son referencias. Ambas variables de referencia son inmutables y no tienen la palabra clave mut
después de let
, lo que significa que no puedo cambiar lo que apuntan. Sin embargo, todavía puedo cambiar el valor al que hacen referencia.
*x_ref = 777;
Si escribe esto, el compilador de Rust no se quejará y el valor de x
(no la referencia en sí) cambiará a 777
. Sin embargo, hay un cuadrado rojo en el esquema que indica que x_ref
carece de la opción de mutabilidad. Entonces, ¿por qué puedo cambiar el valor al que hace referencia?
Volvamos al esquema de let x_ref = &mut x
.
El primer bloque blanco contiene el nombre: x_ref
. El segundo me informa sobre el tipo almacenado en esa variable. En su forma completa, sin anotaciones de tipo implícitas, puedo escribir lo siguiente:
let x_ref: &mut i32 = &mut x;
Puedo interpretar esto como: creemos una variable inmutable llamada x_ref
que contendrá una referencia mutable a i32
y la inicializaremos inmediatamente con la referencia mutable al valor i32
en la variable x
.
let x_ref: &mut i32 = &mut x; let mut z = 0; x_ref = &mut z; // Not allowed!
En términos de los esquemas, quiero cambiar la dirección a la que apunta la flecha en el bloque de código de arriba. Sin embargo, incluso si la variable z
es mutable, no puedo cambiar la flecha porque el problema radica en la inmutabilidad del propio x_ref
.
Para cambiar la dirección de la flecha, necesito modificar la dirección almacenada en la variable x_ref
. Sin embargo, no puedo hacer esto porque la variable es inmutable.
let mut x: i32 = 1337; let mut x_ref: &mut i32 = &mut x; // I've added mut before x_ref let mut z = 0; x_ref = &mut z; // Allowed!
Hay demasiadas instancias de mut
aquí alrededor de x_ref
, ¿verdad? Describámoslos.
let mut x_ref
: estoy creando una variable mutable llamada x_ref
, lo que significa que puedo cambiar su valor más tarde.
&mut i32
: Estoy afirmando que la variable contendrá referencias mutables a algún valor de tipo i32
.
&mut x
: Estoy tomando prestada (obteniendo una referencia a) la variable x
.
Luego, creé una variable llamada z
y le asigné el valor 0
. Luego, cuando escribí x_ref = &mut z
, indiqué que entiendo que x_ref
es una variable mutable que solo puede contener referencias a valores i32
.
Dado que el tipo de z
es i32
, puedo asignar su dirección a la variable x_ref
. Para obtener la dirección de z
, utilicé la sintaxis &mut z
.
Eche un vistazo a =
en la declaración, puede parecer un poco obvio, pero...
let mut x_ref = &mut x;
… Lo veo como un divisor (especialmente si lo gira 90 grados) que divide la declaración en dos subdeclaraciones: izquierda y derecha. El lado izquierdo proporciona información sobre la variable en sí, mientras que el lado derecho nos informa sobre el valor .
Cuando uso el operador de desreferencia *
para cambiar el valor...
*x_ref = 100;
... No cambio el valor de la variable x_ref
. En cambio, estoy cambiando el valor al que hace referencia x_ref
.
Usé mut
con frecuencia antes. ¿Qué pasa si omito algunos de ellos?
let i = 1; let j = 2; let mut k = &i;
¿Puedo cambiar el valor de i
aquí? Usando la técnica del divisor, la respuesta es bastante sencilla. Puedo cambiar el valor de k
(veo mut
en el lado izquierdo), pero el valor (lado derecho) es una referencia inmutable a i
(aquí no hay mut
).
let i = 1; let j = 2; let mut k = &i; k = &j; // This is legal. *k = 3; // This is not.
En este artículo, analizamos los matices de la palabra clave mut
y las referencias. Recuerde, existe una distinción entre una referencia mutable y una variable mutable que contiene una referencia. ¿Nuestro truco?
Usar el signo =
como divisor mental para comprender mejor las tareas en Rust. Esta simple visualización puede aclarar muchas confusiones.