Reputation: 2068
I am creating simple matrix implementation in Rust. I need to iterate over the matrix, getting the coordinates in addition to the value:
for (i, j, elem) in matrix.iter().enumerate() {
...
}
As far as I can see, Iterator::enumerate
is pre-defined and I cannot override it with a custom implementation which is able to return (usize, usize, &T)
. Is there a way to implement a custom enumerate()
method?
Upvotes: 2
Views: 1343
Reputation: 432089
It is correct that you cannot change the signature of Iterator::enumerate
; doing so wouldn't implement the trait as any other consumer would expect. However, you can create an enumerate
method directly on your Matrix
that does what you want:
struct Matrix {
value: u8,
size: usize,
}
impl Matrix {
fn enumerate(&self) -> MatrixEnumerate {
MatrixEnumerate {
matrix: self,
pos: 0,
}
}
}
struct MatrixEnumerate<'a> {
matrix: &'a Matrix,
pos: usize,
}
impl<'a> Iterator for MatrixEnumerate<'a> {
type Item = (usize, usize, &'a u8);
fn next(&mut self) -> Option<(usize, usize, &'a u8)> {
if self.pos < self.matrix.size {
let v = Some((self.pos, self.pos, &self.matrix.value));
self.pos += 1;
v
} else {
None
}
}
}
fn main() {
let m = Matrix {
value: 42,
size: 10,
};
for (x, y, v) in m.enumerate() {
println!("{}, {}: {}", x, y, v);
}
}
Here, I'm skipping the complexity of the matrix and just advancing down the diagonal. Your real implementation has to deal with row-major or column-major iteration and properly wrapping at the end of the row/column.
Upvotes: 6
Reputation: 3509
I think the best way to deal with your problem is to create a new trait that defines a function like enumerate2D() that has the kind of signature you want.
Upvotes: 1