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).