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.
push
: añade un elemento al final[index]
: accede a los elementos (panics!
si es inválido)get(index)
: lo mismo que antes pero devuelve unOption
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…
Los otros metodos tienen implementaciones por defecto. Hay dos tipos:
iterators
: toman iterador, devuelven iteradormap(closure)
: llama a la closure por cada elementofilter(closure)
: devuelve el elemento si la closure devuelvetrue
- Ejemplo (suma uno a cada elemento):
v.iter().map(|x| x + 1).collects();
consumers
: toman un iterador, devuelven elemento
Vec<T>
a Iterator
:
.iter()
: devuelve una referencia inmutable..iter_mut()
: devuelve una referencia mutable..onto_iter()
: own tipes.
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}