Saltar al contenido

Variables y constantes en Rust

· 6 minutos de lectura

Cadena oxidada.

Esta semana he estado aprendiendo rust, no sobre cómo se va formando la capa amarillenta de oxido en el hierro ni el videojuego, sino el lenguaje de programación compilado que está enfocado en la velocidad y la seguridad1.

Rust es un lenguaje compilado, por lo que se puede compilar a un código binario similar a lenguajes como C, C++, y Java, que se diferencian de lenguajes como python y javascript porque estos se ejecutan en tiempo de ejecución.

Variables y su mutabilidad

Todas las variables en Rust son inmutables por defecto.

Esta es una de las formas en la que Rust mantiene un estilo de código para proporcionar seguridad.

Cuando una variable es inmutable, lo que significa que una vez que un valor está vinculado a un nombre, no puede cambiar ese valor.

¿Qué pasa si se declara una variable bajo el supuesto de que su valor nunca cambiará y en un futuro otro en otro bloque de código cambia ese valor?

Es posible que la primera parte del código falle y no haga lo que fue diseñado para hacer. Luego otra persona del equipo puede tener dificultades para saber dónde y cómo ha cambiado ese valor. Esto es lo que intenta evitar Rust.

Probemos esto en el siguiente ejemplo:

fn main() {    let birthdate = "1/1/2000";    println!("The birthdate is: {}", birthdate);    birthdate = "1/1/2022";    println!("The new birthdate is: {}", birthdate);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cargo run
Compiling main v0.1.0 (C:\Users\marco\repositorios\rust\main)
error[E0384]: cannot assign twice to immutable variable `birthdate`
 --> src\main.rs:4:5
  |
2 |     let birthdate = "1/1/2000";
  |         ---------
  |         |
  |         first assignment to `birthdate`
  |         help: consider making this binding mutable: `mut birthdate`
3 |     println!("The birthdate is: {}", birthdate);
4 |     birthdate = "1/1/2022";
  |     ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable

For more information about this error, try `rustc --explain E0384`.
error: could not compile `main` due to previous error

En Rust, el compilador garantiza que cuando declaramos que un valor no cambiará, realmente no cambiará, pero podemos hacer shadowing para que una variable pueda cambiar declarandola de nuevo con let.

fn main() {    let year = 2021;    println!("The year is: {}", year);    let year = 2022;    println!("The new year is: {}", year);}
1
2
3
4
5
6
cargo run
Compiling main v0.1.0 (C:\Users\marco\repositorios\rust\main)
 Finished dev [unoptimized + debuginfo] target(s) in 1.54s
  Running `target\debug\main.exe`
The year is: 2021
The new year is: 2022

Esto puede que no sea conveniente, por lo que la mutabilidad también puede resultar muy útil en muchos casos.

¿Cómo se hace una variable mutable en Rust?

Usando mut, puede cambiar el valor. En algunos casos, una variable mutable es más conveniente que una implementación que solo usa variables inmutables.

fn main() {    let mut birthdate = "1/1/2000";    println!("The birthdate is: {}", birthdate);    birthdate = "1/1/2022";    println!("The new birthdate is: {}", birthdate);}

InformaciónNota: Muy además de permitir que el valor cambie, expresa a los futuros lectores del código al simbolizar que otras partes del código modifican el valor de esta variable.

Variables inmutables vs constantes

Si bien se puede pensar que son iguales, pero no lo son!

Las constantes, como las variables inmutables, son valores que están vinculados a un nombre y no se pueden cambiar. Entonces, ¿cuáles son las diferencias?

  • Las constantes no solo son inmutables por defecto; también son inmutables en todo momento.
  • Las constantes usan la palabra clave const en lugar de la palabra clave let, y se debe anotar el tipo de valor.
  • Las constantes se pueden declarar en cualquier scope, incluyendo el scope global. Este alcance los hace útiles para valores que tienen que estar presentar en varias partes del código.
  • Las constantes solo se pueden usar junto con una expresión constante; no pueden ser el resultado de una llamada de función, una instancia o cualquier otro valor que solo se pueda calcular en tiempo de ejecución.

Advertencia:

Al declarar una variable con let y usar el nombre de una variable en mayusculas, el compilador generará una advertencia.

fn main() {    let PI = 3.14159265359;    println!("{}", PI);}
1
2
3
4
5
6
7
8
9
10
11
12
13
cargo run
warning: variable `PI` should have a snake case name
 --> src\main.rs:2:4
  |
2 |     let PI = 3.14159265359;
  |         ^^ help: convert the identifier to snake case: `pi`
  |
  = note: `#[warn(non_snake_case)]` on by default

warning: `main` (bin "main") generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 0.17s
     Running `target\debug\main.exe`
3.14159265359

Al ser solo una advertencia el programa se ejecutará sin problemas

Correcto:

La forma de nombrar las variables tiene que ser en snake case. Por ejemplo, PI no es correcto, pero pi es correcto.

fn main() {    let pi = 3.14159265359;    println!("{}", pi);}

Error:

Las constantes tienen que llevar el tipo de valor. Si no se pone, el compilador generará un error.

fn main() {    const PI = 3.14159265359;    println!("{}", PI);}
1
2
3
4
5
6
7
8
9
cargo run
Compiling main v0.1.0 (C:\Users\marco\repositorios\rust\main)
error: missing type for `const` item
 --> src\main.rs:2:11
  |
2 |     const PI = 3.14159265359;
  |           ^^ help: provide a type for the constant: `PI: f64`

error: could not compile `main` due to previous error

Correcto:

fn main() {    const PI: f64 = 3.14159265359;    println!("{}", PI);}

¿Por qué usar constantes?

Al reflexionar sobre el uso de constantes y variables inmutables, me pregunté: ¿Por qué no usar siempre variables inmutables? así no me obligaría siempre a escribir el tipo de valor.

La siguiente es una constate válida:

const E: f32 = 2.71828182846;

La siguiente es una variable inmutable válida:

let e = 2.71828182846;

Por lo que algunas de las razones por las que preferiría usar constantes son:

  • No se puede hacer shadowing de una constante volviéndola a declarar.
  • Algunas veces, una variable inmutable puede ser muy útil, pero no es necesario. En ese caso, puede usarse una constante.
  • Las constantes son válidas durante todo el tiempo que se ejecuta un programa, dentro del scope en el que se declararon y en el scope global, lo que quiere decir las puedes poner fuera del main, y se podrían en cualquier parte del programa. De esta forma podemos tener las constantes en un solo lugar y actualizarlas en un futuro fácilmente.

Referencias

  1. Steve Klabnik & Carol Nichols, with contributions from the Rust Community (2018). The Rust Programming Language. [online] Available at: doc.rust-lang.org


Artículos recomendados

Recibirás actualizaciones del blog con temas de programación

Descubre más sitios indie