Algoritmos y Estructuras de Datos Herramientas Lenguaje de programación
!Prog C/C++ Rust
Linux Matemáticas
Mates Discretas
Programación Orientada a Objetos Sistemas Operativos

Listas y Iteradores


[words: 569] [reading time: 3min] [size: 25068 bytes]

Colecciones

Estas se guardan en la heap, por lo que pueden crecer. Otro detalle es que los vectores borrarán todo el contenido, incluidos sus elementos.

1let v = vec![1, 2, 3];
2let v: Vec<tipo> = Vec::new();

Los dos últimos son referencias. Esto puede ser problemático, porque si creamos referencias y añadimos elementos, puede que no sigan en el mismo sitio, por lo que sería referencia invalida, resultando error de compilación.

Podemos usar los siguientes iteradores implícitos:

1for elem in &v     { ... } // Pasar por todo el contenido (lectura)
2for elem in &mut v { ... } // Lo mismo, pero también escribe: desreferencia con *

Strings

Consultar aquí.

Hash map

Guarda un valor relacionado con una clave mediante una función de Hash.

1use collections::HashMap;
2let map = HashMap::new();
3map.insert(key, value); // toma ownership, podemos pasar referencia pero necesita de lifetimes
4map.entry(key).or_insert(value); // añade solo si esta vacio (docs)
5map.get(key); // Devuelve un Option<Some(), None>
6for (key, value) in &/*mut*/ map { ... }

Slices

Este es un tipo de dato que no toma ownership del original. Se trata de una sequencia contigua de elementos de una lista: vectores, strings…

Podemos crear un slice así: &<var>[<init>..<end-exclusive>] (init < end):

1let s = String::from("Hello World");
2let hello = &s[0..5];  // also [..5]
3let world = &s[6..11]; // also [6..]
4let hello_world = &s[..]

Nota: init y end no hacen referencia a la posición de un char en específico, sino que es en bytes.

Aquí estamos creando una referencia a un trozo del String, no al String entero:

El tipo de dato de un String slice se escribe &str, y si declaramos un String literal de las siguiente forma, también será de tipo &str:

1let s = "Hello World";

Un detalle a tener en cuenta, es que podemos convertir Strings de forma muy sencilla a &str, por lo que los hace el tipo ideal para usar como parámetros en funciones:

1fn foo(s: &str) {}
2let s1 = String::from("Hello World");
3let s2 = "Hello World again";
4
5foo(&s1[..]); // or s1.as_str()
6foo(s2);

Los tipos de datos de otras listas que no sean Strings, se escriben por ejemplo así: &[u8].

Iteradores

Permiten pasar por una secuencia de elementos, no importa cuales sean ni como estén guardados, por ejemplo un array, vector, hash map…

1pub trait Iterator {
2  type Item;
3  fn next(&mut self) -> Option<Self::Item>;
4}

Los otros metodos tienen implementaciones por defecto. Hay dos tipos:

Vec<T> a Iterator:

1let v = vec![1, 2, 3];
2for value in v.iter() {
3  println!(value);
4}

Crear nuestros propios iteradores

 1struct Counter {
 2  value: u32
 3}
 4
 5impl Counter {
 6  fn new() -> Counter {
 7    Counter { value : 0 }
 8  }
 9}
10
11impl Iterator for Counter {
12  type Item = u32;
13
14  fn next(&mut self) -> Option<Self::Item> {
15    if self.value < 5 {
16      self.value += 1;
17      Some(self.value)
18    } else {
19      None
20    }
21  }
22}
Anterior: Generics, traits y closures Volver a Rust Siguiente: Macros