I have a struct called Cell
:
pub struct Cell {
x: X, // Some other struct
y: Y, // Some other struct
weight: usize,
}
I was trying to select the top preference cell out of some Row
(a collection of Cell
s):
// Return the top n-matching cells with a positive weight
pub fn select_preference(&mut self) -> Vec<Cell> {
let top = 3;
self.sort();
// After sorting, omit the cells with weight = 0
// And select the top preference cells
self.cells.split(|cell| cell.weight() == 0).take(top)
}
However, I am getting an expected error actually:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:35:9
|
29 | pub fn select_preference(&mut self) -> Vec<Cell> {
| --------- expected `Vec<Cell>` because of return type
...
35 | self.cells.split(|cell| cell.weight() == 0).take(top)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Vec`, found struct `std::iter::Take`
|
= note: expected struct `Vec<Cell>`
found struct `std::iter::Take<std::slice::Split<'_, Cell, [closure@src/lib.rs:35:26: 35:32]>>`
I don't know how to convert the Take
into Vec<Cell>
or &[Cell]
. I know the Take
is some sort of Iterator
but I'm unable to convert it.
First, split
is probably not what you want -- that creates an iterator where each element is a block of nonzero items. You probably want .iter().filter(|cell| cell.weight() != 0)
: iterate over elements of the vector, then filter out those that are nonzero.
To return a vector from an iterator, you need .collect()
. However, this would give a Vec<&Cell>
-- which doesn't quite match your function signature. Since you want a Vec<Cell>
, you also need to clone the elements first to get new cells -- so you can use .cloned()
first. That requires adding #[derive(Clone)]
to Cell
. This is the end result:
#[derive(Clone)]
pub struct Cell {
x: X,
y: Y,
weight: usize,
}
// Return the top n-matching cells with a positive weight
pub fn select_preference(&mut self) -> Vec<Cell> {
let top = 3;
self.sort();
// After sorting, omit the cells with weight = 0
// And select the top preference cells
self.cells.iter().filter(|cell| cell.weight() != 0).take(top).cloned().collect()
}
As a general rule, it's common to always derive Clone
for structs of data.
Other designs are possible too -- you can return the Vec<&Cell>
directly, as the other answer suggests. Finally, you could return an iterator instead of a Vec
; here's how that looks:
pub fn select_preference(&mut self) -> impl Iterator<Item = &Cell> {
let top = 3;
self.sort();
// After sorting, omit the cells with weight = 0
// And select the top preference cells
self.cells.iter().filter(|cell| cell.weight() != 0).take(top)
}