Vectores en Rust – Aprende Rust 11/x

vectores en rust

Cuando vimos los tipos de datos en Rust, uno de ellos fue array. Este es capaz de guardar elementos del mismo tipo en una misma variable, sin embargo, está cerrado a una longitud definida en tiempo de compilación, es decir, no hay manera de que la cantidad de elementos cambie, ni para arriba ni para abajo. Las colecciones en Rust permiten que esto pueda cambiar. En esta entrada trataremos solamente los vectores en Rust.

Los vectores nos permiten guardar datos de un mismo tipo (u32 o f64) en una misma variable. Estos datos son guardados uno junto al otro en memoria. Su definición es Vec<T>.

Crear vectores en Rust

Para crear un vector vacío haremos lo siguiente:

let v: Vec<i32> = Vec::new();

Aquí debemos declararlo de manera explícita porque al estar vacío, el compilador no sabe qué tipo de dato vamos a guardar. Pero agregando i32 entonces sabe que está vacío pero vamos a guardar ese tipo de dato.

Si al menos vamos a inicializar el vector con un valor, lo hacemos así:

let v = vec![1, 2, 3];

Aquí ya le agregamos los valores entonces podemos evitarnos el Vec<i32> y el compilador asignará el tipo de dato por default.

Agregar elementos a un vector

Una vez creado nuestro vector, podemos agregar nuevos valores:

let mut v = Vec::new();

v.push(5);
v.push(6);
v.push(7);
v.push(8);

OJO: para modificar nuestro vector, debemos agregar la palabra mut, como en cualquier otra variable que vaya a cambiar, de lo contrario nos lanzará un error de compilación.

Leer elementos de un vector

Hay dos maneras de obtener un valor leyendo el vector: usando un “index” o con el método get.

let v = vec![1, 2, 3, 4, 5];

let third: i32 = v[2];
println!("The third element is {third}");

Aquí guardamos el tercer elemento (recordemos que iniciamos en 0) en la variable third y luego lo imprimimos.

En caso de que en lugar de v[2] ponemos v[5] (que sería el elemento 6 de la lista) nos tira un error porque no hay un elemento en esa posición. Pero el compilador no nos marca un error, esto es porque usamos un vector no un array.

thread 'main' panicked at src/main.rs:4:25:
index out of bounds: the len is 5 but the index is 5

Para controlar esto, podemos usar el método get. Con este podemos obtener un elemento de un array y ya sea que exista o no, lo evaluaremos con la estructura que vimos en el post anterior: Option<T>:

let v = vec![1, 2, 3, 4, 5];

let third: Option<&i32> = v.get(2);
match third {
    Some(third) => println!("The third element is {third}"),
    None => println!("There is no third element."),
}

Aquí, mediante pattern matching, evaluará el valor que get regresa. Luego aplicaremos match y en caso de que el valor sea un i32 irá a la opción Some.

Cuando pasamos al get, por ejemplo, el valor 5, entonces iría a nuestra opción None.

Ahora veremos algo curioso.

let mut v = vec![1, 2, 3, 4, 5];

let first = &v[0];

v.push(6);

println!("The first element is: {first}");

Aquí vemos que first tiene asignada una referencia al primer elemento de v. De primera instancia parecería que el ejemplo debería funcionar, pero first no es mutable. ¿Y eso qué? Pues que los vectores guardan sus elementos uno junto al otro en la memoria.

Imagina que al hacer v.push(6) ya no había espacio para ese elemento y todo el bloque se tuvo que ir a otra dirección. Entonces first está apuntando a un lugar que ya no es válido, por lo que no podríamos usarlo en nuestro println!.

¿Qué podemos hacer? Pues cambiamos first para que sea también una referencia con &first o modificamos &v[0] a v[0] para que nos copie el valor de esa posición a la variable. Por ejemplo:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let first = v[4];

    v.push(6);

    println!("The first element is: {first}");
}

Iterar vectores en Rust

Para recorrer los elementos de un vector en Rust, usaremos for:

Podemos obtener los valores del vector de manera inmutable:

let v = vec![100, 32, 57];
for i in &v {
    println!("{i}");
}

También podemos hacer cambios sobre cada elemento del vector según avanzamos en la iteración:

let mut v = vec![100, 32, 57];
for i in &mut v {
    *i += 50;
    println!("--> {}", i);
}

Con el operador * obtenemos el valor de esa referencia para modificarlo.

Vectores con enums y structs

Como los vectores solo pueden guardar datos de un mismo tipo, puede ser que no sea tan bueno en algunos casos, ya que tenemos su flexibilidad pero también esta limitación. Sin embargo, podemos crear un enum y asignamos el tipo al vector:

fn main() {
    enum IpAddr {
        V4(u8, u8, u8, u8),
        V6(String),
    }

    let mut ip: Vec<IpAddr> = Vec::new();

    ip.push(IpAddr::V4(192, 168, 1, 0));
    ip.push(IpAddr::V6(String::from("::1")));
}

Este es un ejemplo básico que de cómo se puede usar usando enums.

De la firma forma, podemos usarlo con structs:

fn main() {
    struct Producto {
        nombre: String,
        cantidad: i32,
        precio: f64,
    }

    let mut inventario: Vec<Producto> = Vec::new();

    let prod = Producto {
        nombre: String::from("Mouse XYZ"),
        cantidad: 64,
        precio: 2000.00,
    };
    inventario.push(prod);

    inventario.push(Producto {
        nombre: "Laptop System76".to_string(),
        cantidad: 16,
        precio: 25000.00,
    });
}

Eliminar elementos de un vector

Mediante el método remove del tipo Vec<T> se puede eliminar un elemento de un vector en Rust. Es nos regresa el elemento eliminado y luego lo quita del vector.

Veamos el siguiente ejemplo:

fn main() {
    let mut v = vec![100, 32, 57];

    let eliminado = v.remove(1);
    println!("Eliminado: {eliminado}");

    let nuevo_1 = v[1];
    println!("Nuevo Index 1: {nuevo_1}");
}

Primero, recordar que para poder eliminar, hay que declarar nuestro vector como mut. Eliminamos el elemento en la posición 1.

Si compilamos el resultado es:

Eliminado: 32
Nuevo Index 1: 57

Vemos cómo nos regresa el elemento eliminado (32) y después imprimimos el nuevo valor de la posición 1.

Con esto creo que abarcamos lo más importante de los vectores en Rust.

Puedes consultar más info acá.

Gracias por leer.


Posted

in

, , ,

by