rust - ps4 - ¿Cómo iterar y filtrar una matriz?
rust traduccion (3)
Intento escribir un programa que implique el filtrado y el plegado de matrices. He estado usando The Rust Programming Language , primera edición como referencia, pero no entiendo qué sucede cuando formulo iteradores sobre arreglos. Aquí hay un ejemplo:
fn compiles() {
let range = (1..6);
let range_iter = range.into_iter();
range_iter.filter(|&x| x == 2);
}
fn does_not_compile() {
let array = [1, 4, 3, 2, 2];
let array_iter = array.into_iter();
//13:34 error: the trait `core::cmp::PartialEq<_>` is not implemented for the type `&_` [E0277]
array_iter.filter(|&x| x == 2);
}
fn janky_workaround() {
let array = [1, 4, 3, 2, 2];
let array_iter = array.into_iter();
// Note the dereference in the lambda body
array_iter.filter(|&x| *x == 2);
}
En la primera función, sigo que el iterador sobre el rango no toma posesión, así que debo tomar un &x en la lambda del filter , pero no entiendo por qué el segundo ejemplo con la matriz se comporta de manera diferente.
Como dijeron Shepmaster y bluss, puedes consultar la documentación del tipo de matriz , que menciona:
Las matrices de tamaños del 0 al 32 (inclusive) implementan los siguientes rasgos si el tipo de elemento lo permite:
IntoIterator(implementado para&[T; N]y&mut [T; N])
Como se dice, esto es solo para referencias, y se refleja en su tipo de Item : type Item = &''a T y type Item = &''a mut T
En casos como este, es muy útil obligar al compilador a decirle el tipo de la variable. Activaremos un error de tipo asignando el argumento de cierre a un tipo incompatible:
array_iter.filter(|x| { let () = x; true });
Esto falla con:
error[E0308]: mismatched types
--> src/main.rs:12:33
|
12 | array_iter.filter(|x| { let () = x; true });
| ^^ expected &&{integer}, found ()
|
= note: expected type `&&{integer}`
found type `()`
Ahora sabemos que el tipo de x es a &&{integer} - una referencia a una referencia a algún tipo de número entero. Entonces podemos compararlo con eso:
fn hooray() {
let array = [1, 4, 3, 2, 2];
let array_iter = array.into_iter();
array_iter.filter(|&&x| x == 2);
}
La pregunta ahora se convierte en "¿por qué es una referencia a una referencia"? La versión corta es que el iterador de una matriz devuelve referencias (vea el type Item = &''a T parte). Además, el Iterator::filter pasa una referencia al cierre para evitar el movimiento y, posteriormente, la pérdida de tipos no Copy .
Las matrices son del tipo [T; N] [T; N] en Rust, para cualquier elemento tipo T y un número constante N Es una matriz de tamaño fijo.
Rust no implementa iteradores de valor por defecto para matrices en este momento. Todas las matrices fuerzan a las divisiones (tipo [T] ) y los métodos de división están disponibles en la matriz debido a esto. Las matrices también obtienen el iterador de la sección, que se llama std::slice::Iter<''a, T> y tiene elementos de tipo &''a T : ¡itera por referencia!
Esta es la razón into_iter() cual into_iter() en un Range<i32> produce un iterador de into_iter() e into_iter() en un [i32; 5] [i32; 5] produce un iterador de &i32 .
Si necesita por iteradores de valor para matrices, se han implementado en el ecosistema más amplio, ver (1) y (2) .