Hi everyone!
I have a working example for a struct that implements the IntoIterator
trait (let me know if there are any errors here.)
Example without trait
But now, I would like to create a trait defining the contract to let a developer create custom structs.
I would like the trait to enforce the implementation of IntoIterator
for a reference of the struct in a specific way (Item should be (usize, usize, bool)
)
For what I understand it's a problem of lifetime, because if I change my code and implements the trait for Matrix
and not &'a Matrix
it works Example with Matrix
What do I need to do? And is it the good way to do it?
Thanks.
fn main() {
let mut matrix = Matrix::new();
let mut cells: Vec<_> = matrix.into_iter().collect();
display_matrix(&matrix);
let indexes: [usize; 3] = [1, 1, 2];
for index in indexes.into_iter() {
let cell = cells.remove(*index);
&matrix.set_value(cell.0, cell.1, true);
}
display_matrix(&matrix);
}
trait MatrixTrait
where
Self: IntoIterator<Item = (usize, usize, bool)>,
{
fn new() -> Self;
fn get_value(&self, x: usize, y: usize) -> bool;
fn set_value(&mut self, x: usize, y: usize, value: bool);
}
const WIDTH: usize = 3;
const HEIGHT: usize = 2;
struct Matrix {
matrix: [[bool; HEIGHT]; WIDTH],
}
impl MatrixTrait for Matrix {
fn new() -> Self {
Self {
matrix: [[false; HEIGHT]; WIDTH],
}
}
fn get_value(&self, x: usize, y: usize) -> bool {
if self.is_x_y_valid(x, y) {
self.matrix[x][y]
} else {
panic!("x and y are not valid");
}
}
fn set_value(&mut self, x: usize, y: usize, value: bool) {
if self.is_x_y_valid(x, y) {
self.matrix[x][y] = value
} else {
panic!("x and y are not valid");
}
}
}
impl Matrix {
fn is_x_y_valid(&self, x: usize, y: usize) -> bool {
x < WIDTH && y < HEIGHT
}
}
impl<'a> IntoIterator for &'a Matrix {
type Item = (usize, usize, bool);
type IntoIter = MatrixIterator<'a>;
fn into_iter(self) -> MatrixIterator<'a> {
MatrixIterator {
matrix: self,
iter_x: 0,
iter_y: 0,
}
}
}
pub struct MatrixIterator<'a> {
matrix: &'a Matrix,
iter_x: usize,
iter_y: usize,
}
impl<'a> Iterator for MatrixIterator<'a> {
type Item = (usize, usize, bool);
fn next(&mut self) -> Option<Self::Item> {
if self.matrix.is_x_y_valid(self.iter_x, self.iter_y) {
let x = self.iter_x;
let y = self.iter_y;
self.iter_x += 1;
if self.iter_x == WIDTH {
self.iter_x = 0;
self.iter_y += 1;
}
Some((x, y, self.matrix.get_value(x, y)))
} else {
None
}
}
}
fn display_matrix(matrix: &impl MatrixTrait) {
println!("Matrix");
for cell in matrix.into_iter() {
print!("{}", if cell.2 { 'x' } else { '-' });
if cell.0 == WIDTH - 1 {
println!();
}
}
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0277]: `Matrix` is not an iterator
--> src/main.rs:32:6
|
32 | impl MatrixTrait for Matrix {
| ^^^^^^^^^^^ `Matrix` is not an iterator
|
= help: the trait `std::iter::Iterator` is not implemented for `Matrix`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `Matrix`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.