Hello there!
I'm trying to write a function that takes any iterator and checks for duplicates (the iterators iterate through rows, columns and boxes of a sudoku board). However, I've run into a lifetime error.
Here it is a "minimal" reproduction of the buggy code:
#[derive(Copy, Clone)]
pub struct BoardNum(u8);
impl BoardNum {
pub fn new (value : u8) -> BoardNum {
BoardNum(value)
}
pub fn value(&self) -> u8 {
self.0
}
}
#[derive(Copy, Clone)]
pub struct Board {
values : [Option<BoardNum>; 81],
}
impl Board {
pub fn new() -> Board {
Board{values : [None; 81]}
}
pub fn get(&self, row : usize, column : usize) -> &Option<BoardNum> {
&self.values[row * 9 + column]
}
pub fn row(&self, row : usize) -> Row {
Row::new(row, &self)
}
fn is_valid(&self) -> bool {
for i in 0..9 {
if no_duplicate(Box::new(self.row(i))) { //TODO
return false;
}
}
true
}
}
fn no_duplicate(iter : Box<dyn Iterator<Item = &Option<BoardNum>>>) -> bool {
let mut value_set = [false; 9];
for value in iter {
if let Some(board_num) = value {
let index = (board_num.value() - 1) as usize;
if value_set[index] {
return false; // We have a duplicate!
} else {
value_set[index] = true;
}
}
}
true
}
pub struct Row<'a> {
row : usize,
current_column : usize,
board : &'a Board,
}
impl<'a> Row<'a> {
pub fn new(row: usize, board: &'a Board) -> Self {
Self { row, current_column : 0, board }
}
}
impl<'a> Iterator for Row<'a> {
type Item = &'a Option<BoardNum>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_column != 9 {
let res = Some(self.board.get(self.row, self.current_column));
self.current_column += 1;
res
} else {
None
}
}
}
And here it is the error that cargo check
gives:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:35:43
|
35 | if no_duplicate(Box::new(self.row(i))) { //TODO
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 33:5...
--> src/lib.rs:33:5
|
33 | / fn is_valid(&self) -> bool {
34 | | for i in 0..9 {
35 | | if no_duplicate(Box::new(self.row(i))) { //TODO
36 | | return false;
... |
40 | | true
41 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:35:38
|
35 | if no_duplicate(Box::new(self.row(i))) { //TODO
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> src/lib.rs:35:29
|
35 | if no_duplicate(Box::new(self.row(i))) { //TODO
| ^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = &std::option::Option<BoardNum>> + 'static)>`
found `std::boxed::Box<dyn std::iter::Iterator<Item = &std::option::Option<BoardNum>>>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
error: could not compile `sudoku`.
To learn more, run the command again with --verbose.
I have a couple of questions:
- Can this be done with a template instead of
Box<dyn>
? - There is a mention of a static lifetime, which is most likely the problem here. Where does this requirement comes from?
- How can I fix the code?
Thank you for your time!