function - patron - recorrer arraylist java foreach
¿Cómo escribir una función Rust que tome un iterador? (2)
Me gustaría escribir una función que acepte un iterador y devuelva los resultados de algunas operaciones en él. Específicamente, estoy tratando de iterar sobre los valores de un HashMap
:
use std::collections::HashMap;
fn find_min<''a>(vals: Iterator<Item=&''a u32>) -> Option<&''a u32> {
vals.min()
}
fn main() {
let mut map = HashMap::new();
map.insert("zero", 0u32);
map.insert("one", 1u32);
println!("Min value {:?}", find_min(map.values()));
}
Pero Ay:
error: the `min` method cannot be invoked on a trait object
--> src/main.rs:4:10
|
4 | vals.min()
| ^^^
error[E0277]: the trait bound `std::iter::Iterator<Item=&''a u32> + ''static: std::marker::Sized` is not satisfied
--> src/main.rs:3:17
|
3 | fn find_min<''a>(vals: Iterator<Item = &''a u32>) -> Option<&''a u32> {
| ^^^^ `std::iter::Iterator<Item=&''a u32> + ''static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=&''a u32> + ''static`
= note: all local variables must have a statically known size
error[E0308]: mismatched types
--> src/main.rs:11:41
|
11 | println!("Min value {:?}", find_min(map.values()));
| ^^^^^^^^^^^^ expected trait std::iter::Iterator, found struct `std::collections::hash_map::Values`
|
= note: expected type `std::iter::Iterator<Item=&u32> + ''static`
found type `std::collections::hash_map::Values<''_, &str, u32>`
Me sale el mismo error si trato de pasar por referencia; si utilizo un Box
, recibo errores de por vida.
Desea utilizar los genéricos aquí:
fn find_min<''a, I>(vals: I) -> Option<&''a u32>
where
I: Iterator<Item = &''a u32>,
{
vals.min()
}
Los rasgos se pueden usar de dos maneras: como límites en los parámetros de tipo y como objetos de rasgo. El libro The Rust Programming Language tiene un capítulo sobre los traits y un capítulo sobre los objetos de rasgo que explican estos dos casos de uso.
Además, a menudo desea tomar algo que implemente IntoIterator
ya que esto puede hacer que el código llame mejor a su función:
fn find_min<''a, I>(vals: I) -> Option<&''a u32>
where
I: IntoIterator<Item = &''a u32>,
{
vals.into_iter().min()
}
Este comportamiento es un poco intuitivo de aquellos con un fondo de Python en lugar de, por ejemplo, un fondo C ++, así que déjenme aclarar un poco.
En Rust, los valores se almacenan conceptualmente dentro del nombre que los une. Por lo tanto, si escribes
let mut x = Foo { t: 10 };
let mut y = x;
x.t = 999;
y todavía será 10
.
Entonces cuando escribes
let x: Iterator<Item=&''a u32>;
(o lo mismo en la lista de parámetros de función), Rust necesita asignar suficiente espacio para cualquier valor de tipo Iterator<Item=&''a u32>
. Incluso si esto fuera posible, no sería eficiente.
Entonces, lo que hace Rust es ofrecerle la opción de
Pon el valor en el montón, ej. con
Box
, que proporciona semántica al estilo de Python. Luego puede tomar genéricamente con&mut Iterator<Item=&''a u32>
.Especialice cada invocación de función para cada tipo posible para satisfacer el límite. Esto es más flexible, ya que una referencia de rasgo es una especialización posible, y le da al compilador más oportunidades de especialización, pero significa que no puede tener despacho dinámico (donde el tipo puede variar dependiendo de los parámetros de tiempo de ejecución).