paint-brush
¿Referencias mutables o variables mutables? Decodificando el mut-mut-mut de Rustpor@charnog
904 lecturas
904 lecturas

¿Referencias mutables o variables mutables? Decodificando el mut-mut-mut de Rust

por Denis Gonchar5m2023/09/23
Read on Terminal Reader

Demasiado Largo; Para Leer

La seguridad de la memoria de Rust tiene sus raíces en sus mecanismos de propiedad y préstamo. Este artículo profundiza en las complejidades de la palabra clave mut, distinguiendo entre referencias mutables y variables mutables. ¿La conclusión clave? No todos los muts son iguales: las referencias mutables permiten alterar el valor al que apuntan, mientras que las variables mutables con referencias pueden cambiar hacia dónde apuntan. Un práctico truco de visualización que utiliza el signo = simplifica la comprensión de estas distinciones.
featured image - ¿Referencias mutables o variables mutables? Decodificando el mut-mut-mut de Rust
Denis Gonchar HackerNoon profile picture

Introducción

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.

Las variables

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 .

Nombre de pila; segundo - tipo, tercero - valor, cuarto - bandera mut.

Las referencias

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;


Creé dos referencias (o "tomé prestadas" en términos de Rust). Una de ellas es una referencia mutable y la otra es una referencia de solo lectura. Creemos un esquema para eso nuevamente.


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 .


Esto significa que puedo modificar el valor al que apunta, pero no puedo alterar el valor (o dirección) de la referencia. En otras palabras, no puedo escribir algo como:

 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.


¡Vamos a hacerlo!

 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.


  1. let mut x_ref : estoy creando una variable mutable llamada x_ref , lo que significa que puedo cambiar su valor más tarde.


  2. &mut i32 : Estoy afirmando que la variable contendrá referencias mutables a algún valor de tipo i32 .


  3. &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 .


El esquema.

El truco mental

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 .

Referencias inmutables

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 ).


Por lo tanto…

 let i = 1; let j = 2; let mut k = &i; k = &j; // This is legal. *k = 3; // This is not.


El esquema.

Conclusión

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.


¡Feliz codificación!