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