Variables y Mutabilidad
- Se declaran utilizando
letoconstseguido del tipo de dato - Si no se especifica el tipo, el compilador los puede inferir y asignar los tipos por defecto, como
i32para los enteros - Son inmutables por defecto
// let
let x = 10; // default: i32
let y: u8 = 5;
// const
const PI: f32 = 3.1416;
const CODE: &str = "123";
- No se pueden leer o manipular variables no inicializadas
- Pero, si se pueden declarar e inicializar después, entonces ya se podrá leer o manipular la variable
// Error
let x: i32;
println!("Num: {x}");
// Correct
let y: i32;
y = 10;
prinln!("Num: {y}");
let
Inmutable
- Las variables, cuando se crean o inicializan, son inmutables por defecto
fn main() {
let name: &str = "Rust";
let x: u8 = 5;
println!("El valor de x: {x}");
x = 6; // Error, no se puede reasignar el valor de una variable
println!("El nuevo valor de x: {x}"); }
}
Mutable
- Agregando
mutal crear la variable - Al agregar
muttambién transmite la intención a los futuros lectores del código al indicar que otras partes del código cambiarán el valor de esta variable
fn main() {
let mut num: u16 = 10; // mut para poder modificarla
println!("El numero es: {}", num);
num = 20; // Se puede reasignar
println!("El numero ahora es: {}", num);
}
const
- Constantes en tiempo de compilación
- Se debe especificar el tipo de dato
- Similar a las variables inmutables
- No se puede utilizar
mutpara hacerlas mutables - Los valores de la variable no pueden cambiar y siempre son inmutables
- TODO_MAYUSCULA_CON_GUION_BAJO
- Se puede declarar en cualquier ámbito (scope global o local)
- Las constantes son válidas durante todo el tiempo que se ejecuta el programa, dentro del ámbito en que se declararon
const LIMIT: i32 = 20;
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
const CODE: &str = "123";
//const mut z: i32 = 20; // Error
Diferencia entre const y let
constno es solo una variable inmutable, sino una constante en tiempo de compilaciónconstno puede depender de cálculos en tiempo de ejecución ni de entrada del usuarioletse define en tiempo de ejecuciónletpuede cambiar dependiendo de la lógica del programaconst X: i32 = 5;debe ser conocido en tiempo de compilación, lo que lo hace más restrictivo.let y = 5;(sinmut) es inmutable, pero su valor puede determinarse en tiempo de ejecución.
Si se hiciera const obligatorio para inmutabilidad, se perdería la flexibilidad de valores inmutables determinados en tiempo de ejecución.
const MAX_USERS: u32 = 100; // Esto es fijo, conocido en compilación
const NAME: &str = "Rust";
let user_id = get_user_id(); // Se obtiene en tiempo de ejecución
Shadowing
- Se puede declarar una variable con el mismo nombre de una variable anterior
- La primera variable se sobreescribirá por la segunda
- Se debe escribir
let(como se declaran las variables normalmente) ya que sino entonces únicamente se estaría actualizando o usando el valor de la variable - Se puede crear ámbitos donde se cambia el valor pero no es de forma global o general
fn main() {
let x = 5;
let x = x + 1; // Shadowing
{
let x = x * 2; // Shadowing interno
println!("X en el scope interno: {x}"); //12
}
println!("El valor de X: {x}"); // 6
}
- Se puede cambiar el tipo de dato de la variable ya que se está creando una nueva variable
fn main() {
// Simulando entrada del usuario con espacios extra
let input = " 42.5 ";
println!("Valor original: '{}'", input); // ' 42.5 '
// Shadowing 1: String -> String (trim)
let input = input.trim();
println!("Shadowing 1: String = '{}'", input); // '42.5'
// Shadowing 2: String -> f64 (parse)
let input: f64 = input.parse().expect("No es un número válido");
println!("Shadowing 2: f64 = {}", input); // 42.5
// Shadowing 3: f64 -> i32 (round y conversión)
let input = input.round() as i32;
println!("Shadowing 3: i32 = {}", input); // 42
// Shadowing 4: i32 -> String (formateo)
let input = format!("El resultado es: {}", input);
println!("Shadowing 4: String = {}", input); // "El resultado es: 42"
}
fn other_example() {
let number = "T-H-R-E-E";// "number" es de tipo "str"
println!("Spell a number: {number}");
// Using variable shadowing
let number = 3; // "number" ahora es de tipo i32
println!("Number plus two is: {}", number + 2);
}
Diferencia con mut
- Se puede declarar una variable con el mismo nombre que una variable anterior
- Se puede cambiar el tipo de dato de la variable ya que se está creando una nueva variable
- La primera variable queda sombreada o sobreescrita por la segunda
- No es lo mismo que agregar
muta la variable (que actualizaría el valor de la variable) mutno permite el cambio de tipo de variable
let x: i32 = 10;
//x = 20; // Mutable, si tuviera la palabra mut
let x: i32 = x * 2; // Shadowing
fn main() {
let x = 5;
let x = x + 1; // 6
{
// Ya que es un nuevo scope, al salir de el se pierde la variable x
let x = x * 2; // 6 * 2 = 12
println!("El valor de x en el scope interno es: {x}");
}
println!("El valor de x en la función principal es: {x}"); // 6
}