Variables y Mutabilidad

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Bienvenido a Variables y Mutabilidad. Esta práctica es parte del Rust Book. Puedes practicar tus habilidades de Rust en LabEx.

En esta práctica, exploramos el concepto de mutabilidad en Rust, discutimos cómo las variables son inmutables por defecto y cómo hacerlas mutables usando la palabra clave mut, y destacamos la importancia de la inmutabilidad para la seguridad y la concurrencia, mientras que todavía reconocemos la utilidad de la mutabilidad en ciertas situaciones.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/BasicConceptsGroup -.-> rust/mutable_variables("Mutable Variables") rust/BasicConceptsGroup -.-> rust/constants_usage("Constants Usage") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") subgraph Lab Skills rust/variable_declarations -.-> lab-100387{{"Variables y Mutabilidad"}} rust/mutable_variables -.-> lab-100387{{"Variables y Mutabilidad"}} rust/constants_usage -.-> lab-100387{{"Variables y Mutabilidad"}} rust/integer_types -.-> lab-100387{{"Variables y Mutabilidad"}} rust/function_syntax -.-> lab-100387{{"Variables y Mutabilidad"}} rust/expressions_statements -.-> lab-100387{{"Variables y Mutabilidad"}} rust/method_syntax -.-> lab-100387{{"Variables y Mutabilidad"}} end

Variables y Mutabilidad

Como se mencionó en "Almacenar valores con variables", por defecto, las variables son inmutables. Esto es una de las muchas sugerencias que Rust te da para escribir tu código de manera que aproveche la seguridad y la fácil concurrencia que ofrece Rust. Sin embargo, todavía tienes la opción de hacer que tus variables sean mutables. Vamos a explorar cómo y por qué Rust te anima a favorecer la inmutabilidad y por qué a veces es posible que desees optar por la mutabilidad.

Cuando una variable es inmutable, una vez que un valor está vinculado a un nombre, no puedes cambiar ese valor. Para ilustrar esto, genera un nuevo proyecto llamado variables en tu directorio proyecto usando cargo new variables.

Luego, en tu nuevo directorio variables, abre src/main.rs y reemplaza su código con el siguiente código, que todavía no se compilará:

Nombre de archivo: src/main.rs

fn main() {
    let x = 5;
    println!("El valor de x es: {x}");
    x = 6;
    println!("El valor de x es: {x}");
}

Guarda y ejecuta el programa usando cargo run. Deberías recibir un mensaje de error sobre un error de inmutabilidad, como se muestra en esta salida:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: no se puede asignar dos veces a la variable inmutable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         primera asignación a `x`
  |         ayuda: considerar hacer este enlace mutable: `mut x`
3 |     println!("El valor de x es: {x}");
4 |     x = 6;
  |     ^^^^^ no se puede asignar dos veces a la variable inmutable

Este ejemplo muestra cómo el compilador te ayuda a encontrar errores en tus programas. Los errores del compilador pueden ser frustrantes, pero en realidad solo significan que tu programa no está haciendo lo que quieres de manera segura todavía; no significan que no seas un buen programador. Los Rustaceos experimentados todavía obtienen errores del compilador.

Recibiste el mensaje de error no se puede asignar dos veces a la variable inmutablex`porque intentaste asignar un segundo valor a la variable inmutablex`.

Es importante que obtengamos errores en tiempo de compilación cuando intentamos cambiar un valor que se designa como inmutable porque esta situación puede conducir a errores. Si una parte de nuestro código opera con la suposición de que un valor nunca cambiará y otra parte de nuestro código cambia ese valor, es posible que la primera parte del código no haga lo que se diseñó para hacer. La causa de este tipo de error puede ser difícil de localizar después de los hechos, especialmente cuando la segunda parte del código cambia el valor solo a veces. El compilador de Rust garantiza que cuando dices que un valor no cambiará, realmente no cambiará, por lo que no tienes que preocuparte por ello. Tu código es por lo tanto más fácil de entender.

Pero la mutabilidad puede ser muy útil y puede hacer que el código sea más conveniente de escribir. Aunque las variables son inmutables por defecto, puedes hacerlas mutables agregando mut al frente del nombre de la variable, como lo hiciste en el Capítulo 2. Agregar mut también transmite el propósito a futuros lectores del código al indicar que otras partes del código cambiarán el valor de esta variable.

Por ejemplo, cambiemos src/main.rs al siguiente:

Nombre de archivo: src/main.rs

fn main() {
    let mut x = 5;
    println!("El valor de x es: {x}");
    x = 6;
    println!("El valor de x es: {x}");
}

Cuando ejecutamos el programa ahora, obtenemos esto:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.30s
     Running `target/debug/variables`
El valor de x es: 5
El valor de x es: 6

Estamos permitidos cambiar el valor vinculado a x de 5 a 6 cuando se usa mut. En última instancia, decidir si usar mutabilidad o no depende de ti y depende de lo que consideres más claro en esa situación particular.

Constantes

Como las variables inmutables, las constantes son valores que están vinculados a un nombre y no se les permite cambiar, pero hay algunas diferencias entre las constantes y las variables.

En primer lugar, no se te permite usar mut con constantes. Las constantes no solo son inmutables por defecto, sino que siempre lo son. Declaras constantes usando la palabra clave const en lugar de la palabra clave let, y el tipo del valor debe ser anotado. Cubriremos tipos y anotaciones de tipos en "Tipos de datos", así que no te preocupes por los detalles por ahora. Simplemente sé que siempre debes anotar el tipo.

Las constantes se pueden declarar en cualquier ámbito, incluyendo el ámbito global, lo que las hace útiles para valores que muchas partes del código necesitan conocer.

La última diferencia es que las constantes solo pueden establecerse en una expresión constante, no en el resultado de un valor que solo se podría calcular en tiempo de ejecución.

Aquí hay un ejemplo de declaración de constante:

const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

El nombre de la constante es THREE_HOURS_IN_SECONDS y su valor se establece en el resultado de multiplicar 60 (el número de segundos en un minuto) por 60 (el número de minutos en una hora) por 3 (el número de horas que queremos contar en este programa). La convención de nombres de Rust para las constantes es usar todas las letras mayúsculas con guiones bajos entre las palabras. El compilador es capaz de evaluar un conjunto limitado de operaciones en tiempo de compilación, lo que nos permite elegir escribir este valor de una manera más fácil de entender y verificar, en lugar de establecer esta constante en el valor 10.800. Consulte la sección de evaluación de constantes de la Referencia de Rust en https://doc.rust-lang.org/reference/const_eval.html para obtener más información sobre qué operaciones se pueden usar al declarar constantes.

Las constantes son válidas durante todo el tiempo que un programa se ejecuta, dentro del ámbito en el que se declararon. Esta propiedad hace que las constantes sean útiles para valores en el dominio de su aplicación que varias partes del programa pueden necesitar conocer, como el número máximo de puntos que cualquier jugador de un juego puede ganar, o la velocidad de la luz.

Denominar los valores codificados en el código que se usan en todo el programa como constantes es útil para transmitir el significado de ese valor a futuros mantenedores del código. También ayuda a tener solo un lugar en el código donde tendrías que cambiar si el valor codificado en el código necesitara actualizarse en el futuro.

Sombreado

Como viste en el tutorial del juego de adivinanza del Capítulo 2, puedes declarar una nueva variable con el mismo nombre que una variable anterior. Los Rustaceans dicen que la primera variable es sombreada por la segunda, lo que significa que la segunda variable es lo que el compilador verá cuando uses el nombre de la variable. En efecto, la segunda variable sombreada la primera, tomando cualquier uso del nombre de la variable para sí misma hasta que ya sea ella misma sombreada o el ámbito termine. Podemos sombrear una variable usando el mismo nombre de la variable y repitiendo el uso de la palabra clave let de la siguiente manera:

Nombre de archivo: src/main.rs

fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("El valor de x en el ámbito interno es: {x}");
    }

    println!("El valor de x es: {x}");
}

Este programa primero asocia x a un valor de 5. Luego crea una nueva variable x repitiendo let x =, tomando el valor original y sumando 1 para que el valor de x sea entonces 6. Luego, dentro de un ámbito interno creado con llaves, la tercera declaración let también sombrea x y crea una nueva variable, multiplicando el valor anterior por 2 para dar a x un valor de 12. Cuando ese ámbito finaliza, el sombreado interno termina y x vuelve a ser 6. Cuando ejecutamos este programa, se mostrará lo siguiente:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/variables`
El valor de x en el ámbito interno es: 12
El valor de x es: 6

El sombreado es diferente de marcar una variable como mut porque obtendremos un error en tiempo de compilación si accidentalmente intentamos volver a asignar a esta variable sin usar la palabra clave let. Al usar let, podemos realizar algunas transformaciones en un valor pero que la variable sea inmutable después de que se hayan completado esas transformaciones.

La otra diferencia entre mut y el sombreado es que, ya que estamos efectivamente creando una nueva variable cuando usamos de nuevo la palabra clave let, podemos cambiar el tipo del valor pero reutilizar el mismo nombre. Por ejemplo, digamos que nuestro programa le pide a un usuario que muestre cuántos espacios quiere entre algunos textos ingresando caracteres de espacio, y luego queremos almacenar esa entrada como un número:

let spaces = "   ";
let spaces = spaces.len();

La primera variable spaces es de tipo cadena y la segunda variable spaces es de tipo número. El sombreado así nos ahorra tener que inventar diferentes nombres, como spaces_str y spaces_num; en cambio, podemos reutilizar el nombre más simple spaces. Sin embargo, si intentamos usar mut para esto, como se muestra aquí, obtendremos un error en tiempo de compilación:

let mut spaces = "   ";
spaces = spaces.len();

El error dice que no se nos permite mutar el tipo de una variable:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0308]: tipos no coincidentes
 --> src/main.rs:3:14
  |
2 |     let mut spaces = "   ";
  |                      ----- debido a este valor se esperaba
3 |     spaces = spaces.len();
  |              ^^^^^^^^^^^^ esperado `&str`, encontrado `usize`

Ahora que hemos explorado cómo funcionan las variables, veamos más tipos de datos que pueden tener.

Resumen

¡Felicidades! Has completado la práctica de Variables y Mutabilidad. Puedes practicar más prácticas en LabEx para mejorar tus habilidades.