Convert Take to Vec<T> or to &[T] - vector

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 Cells).
// 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]>>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error
I don't know how to convert the Take into Vec<Cell> or &[Cell]. I know the Take is some sort of Iterator but unable to convert it :>
Rust Playground

Returning a vector of references to the relevant cells is, I think, the most idiomatic way to do this as it allows using iterators. You can then write:
pub fn select_preference(&mut self) -> Vec<&Cell> {
let top = 3;
self.sort();
self.cells.iter().filter(|cell| cell.weight() != 0).take(top).collect()
}
You can even sort only the iterator and not the Vec<Cell> itself.
Returning a slice is difficult as a slice must always refer to a contiguous part of a sequence. This will always be the case here due to the sorting of cells, however the iterator methods don't take this into account and so cannot be used. One way you could do it is:
pub fn select_preference(&mut self) -> &[Cell] {
let mut top = 3;
self.sort();
let mut ret = &self.cells[..cmp::min(self.cells.len(), top)];
while ret[ret.len() - 1].weight() == 0 {
ret = &ret[..ret.len() - 1];
}
ret
}
But it is probably evident that this is not very idiomatic Rust.

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

Related

Differences between the different ways to access and modify elements in a vector

I defined an enum called Cell and an struct named Universe:
enum Cell {
Dead,
Alive,
}
struct Universe {
width: u64,
height: u64,
cells: Vec<Cell>,
}
and I defined a method called randomize, like this:
impl Universe {
pub fn randomize(&mut self) {
for cell in self.cells.iter_mut() {
let cell_is_alive = rand::thread_rng().gen_bool(0.5);
if cell_is_alive {
*cell = Cell::Alive;
}
}
}
}
and the method works as I expected. But here is the problem, if I change the method to:
impl Universe {
pub fn randomize(&mut self) {
for mut cell in self.cells.iter_mut() {
let cell_is_alive = rand::thread_rng().gen_bool(0.5);
if cell_is_alive {
*cell = Cell::Alive;
}
}
}
}
(mut after the for)
the code also works as well. Then, if I change the code to:
impl Universe {
pub fn randomize(&mut self) {
for &mut cell in self.cells.iter_mut() {
let cell_is_alive = rand::thread_rng().gen_bool(0.5);
if cell_is_alive {
*cell = &mut Cell::Alive;
}
}
}
}
the compiler says the following
error[E0614]: type `game::Cell` cannot be dereferenced
--> src\game.rs:28:17
|
28 | *cell = &mut Cell::Alive;
| ^^^^^
and the weirdest for me is the following:
impl Universe {
pub fn randomize(&mut self) {
for mut cell in self.cells.iter_mut() {
let cell_is_alive = rand::thread_rng().gen_bool(0.5);
if cell_is_alive {
cell = &mut Cell::Alive;
}
}
}
}
The previous one compiles but appears do nothing at all to cells.
What difference made the mut after the for in the second version?
Why I can't dereference the cell in the third version when I did exactly that (I think) in the first one?
Why suddenly the last version compiles perfectly but doesn't randomize cells?
Thanks to let () = cell; in your code, you can trigger errors with an explicit description of the type of cell (this trick helps me a lot when I am lost).
for cell in self.cells.iter_mut() declares cell as a &mut Cell; this is what you want for the following operations, i.e. mutate the Cells that are inside the vector.
for mut cell in self.cells.iter_mut() also declares cell as a &mut Cell but the mut keyword you added applies to the binding. You can make cell point to something else after: cell = &mut another_Cell;.
If you know C, this is Cell *cell; instead of Cell * const cell;, the const after * applies to the pointer itself not the pointed-to object (const before the * applies to the pointed-to object, like the difference between &mut and &).
for &mut cell in self.cells.iter_mut() declares cell as a Cell because the &mut cell part is a pattern matching with what each iteration provides. Since we saw that each iteration provided an &mut Cell, matching this with your pattern makes that your cell should be a Cell (a value, not a reference).
Your Cell type is not Copy so this operation should consume the Cell from the vector, but it is impossible since we use the vector through a borrow.
Even is we decided to change all the code in order to consume the Universe and its vector, *cell = ... would not be allowed since cell would be a value (not a mutable reference).
These three situations out of the context:
let r = &mut something;: r points once for all to something and can mutate it.
let mut r = &mut something;: r points to something, can mutate it, but can be reassigned later in order to point to something else (and mutate it also).
if let &mut v = &mut something {: v is a copy of something (if allowed).
Rust tries to match patterns, basically.
for cell in cells.iter_mut()
cells.iter_mut() returns a &mut Cell, so that's the type given to cell. You can't mutate cell, only the value it points to.
for mut cell in cells.iter_mut()
Pattern matching doesn't work here, so cell is now just a mut &mut Cell. Now you can change the value of cell, i.e., make it a mutable pointer to some other Cell. You didn't use that in your second example, so it works identically to your 1st case. In your 4th example, you try to assign &mut Cell::Alive to cell, which is a mut &mut Cell. So basically you a creating a new instance of Cell, and giving cell a mutable pointer to it. You never mutated the actual list of cells.
for &mut cell in cells.iter_mut()
This is where the pattern matching comes into play. The Iterator returns an &mut Cell, and you're trying to assign it to &mut cell, so Rust makes cell a mut Cell pointing into cells, so you can just do cell = Cell::Alive without dereferencing.

Recursive generator in Rust

I am trying to port this python prime number generator to rust using rust generators and this generator-to-iterator wrapper.
My problem is that the original implementation is recursive, and I didn't manage to get passed the following error:
error[E0720]: opaque type expands to a recursive type
--> src/main.rs:27:29
|
27 | fn recursive_generator() -> impl Iterator<Item = u64> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `GeneratorToIterator<[generator#src/main.rs:28:25:
48:6 {u64, (), impl std::iter::Iterator}]>`
Below is the implementation of the recursive generator producing this error:
fn recursive_generator() -> impl Iterator<Item = u64> {
GeneratorToIterator(move || {
// Yield a few values
yield 1;
yield 2;
yield 3;
// Initialize the inner generator
let mut inner_value: u64 = 0;
let mut inner_generator = recursive_generator();
// Get the first value of the inner generator
match inner_generator.next(){
Some(x) => inner_value += x,
None => {},
}
// Yield some other values
yield 4;
yield 5;
yield 6;
})
}
The full implementation (with the GeneratorToIterator definition) can be found here.
I found this related question but I did not manage to compile their gen_to_iter function.
EDIT: Thanks to #bluss answer, I've finally been able to implement a working version of the prime number generator in rust.
The error explanation E0720 mentions that an impl Trait type must expand to one that doesn't contain other impl Trait types, but here the type is of course recursive, since that's the point.
This can be worked around by using boxed trait objects instead - Box<Iterator<Item=u64>> works well here and avoids the problem.
Either adjust recursive_generator to return Box<Iterator<Item=u64>>, or change the line of the recursive call to use the boxed iterator just for that recursive case.

How to update all the values in a BTreeSet?

I have collection which is a field in a struct in some module. I want to update all the values in the collection from another module.
I wrote some code to mimic what I want to achieve. It's shortened a bit, but I think it has all needed parts. There is no struct holding the collection in this code, but imagine this is a getter which returns the collection. I added in comments how I think it should look.
pub mod pos {
use std::cmp::{Ordering, PartialEq};
#[derive(PartialOrd, PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub struct Pos {
pub x: i32,
pub y: i32,
}
#[allow(dead_code)]
impl Pos {
pub fn of(x: i32, y: i32) -> Self {
Self { x, y }
}
pub fn offset(&mut self, pos: &Self) -> Self {
self.x += pos.x;
self.y += pos.y;
*self
}
}
impl Ord for Pos {
fn cmp(&self, other: &Self) -> Ordering {
if self.x < other.x {
Ordering::Less
} else if self.eq(other) {
Ordering::Equal
} else {
Ordering::Greater
}
}
}
}
mod test {
use crate::pos::Pos;
use std::collections::BTreeSet;
#[test]
fn test_iterators() {
let mut data_in_some_strct: BTreeSet<Pos> = BTreeSet::new();
data_in_some_strct.insert(Pos::of(1, 1));
data_in_some_strct.insert(Pos::of(2, 2));
data_in_some_strct.insert(Pos::of(3, 3));
data_in_some_strct.insert(Pos::of(4, 4));
// mimic getter call ( get_data(&mut self) -> &BTreeSet<Pos> {...}
// let set = data_in_some_strct; // works, but not a reference
let set = &data_in_some_strct; // doesn't work, How to adjust code to make it work??
data_in_some_strct = set
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
assert_eq!(data_in_some_strct.contains(&Pos::of(2, 1)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(3, 2)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(4, 3)), true);
assert_eq!(data_in_some_strct.contains(&Pos::of(5, 4)), true);
}
}
Playground
error[E0596]: cannot borrow `*p` as mutable, as it is behind a `&` reference
--> src/lib.rs:56:26
|
56 | .map(|mut p| p.offset(&Pos::of(1, 0)))
| - ^ `p` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| |
| help: consider changing this to be a mutable reference: `&mut pos::Pos`
I managed to make it work without borrowing, but I would like to make it work with borrowing. I guess there is more then one way to achieve it. Comments to help my Rust brain dendrites connect are welcome.
You can't mutate items that are part of a HashSet or BTreeSet because the value of the items determines how they are stored and accessed. If you mutate them then, as Stargateur mentioned, you would break the mechanics of the collection. In the case of a HashSet, you would change the hash of the item, which determines the location where the data is stored. In the case of a BTreeSet, the algorithm is based on how the items are sorted.
You are able to do it by taking ownership because you consume the original set and produce a new, well-formed one. You can't take ownership of a borrowed value because that would leave behind a dangling pointer, which Rust will not let you do.
One possible solution is to temporarily replace the original set with an empty one. Then you can take ownership of its contents, as in your working code, and finally write the newly updated set over the original:
let set = std::mem::replace(&mut data_in_some_strct, BTreeSet::new());
data_in_some_strct = set.into_iter()
.map(|mut p| p.offset(&Pos::of(1,0)))
.inspect(|p| println!("{:?}", *p))
.collect();
BTreeSet doesn't implement impl<'a, T> IntoIterator for &'a mut BTreeSet<T> (that would break the tree).
You can only do this with types that implement IntoIterator with mut like impl<'a, T> IntoIterator for &'a mut Vec<T>, example.
For sets that are not a field of a struct
Even std::mem::replace is not required.
data_in_some_strct = data_in_some_strct
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
Explanation
We essentially build an iterator for moving out the BTreeSet’s contents.
Then we call .map() over the elements and call the required methods.
It should be noted that it works here because .offset(...) returns Self. If the method does not return Self, you can simply write:
// ...
.map(|mut p| {
p.offset(&Pos::of(1, 0));
p
})
// ...
At last, we use .collect() to construct a BTreeSet with all newly "updated" values.
For sets that are a field of a struct
Let's assume that the field's name is data_in_some_strct of some given struct Foobar.
struct Foobar {
data_in_some_strct: BTreeSet<Pos>,
}
Let's say hypothetically we also have method called Foobar::update() that updates the values in the set.
impl Foobar {
fn update(&mut self) {
// ...
}
}
To update the set from within, we'd have to use std::mem::take().
fn update(&mut self) {
self.data_in_some_strct = std::mem::take(&mut self.data_in_some_strct)
.into_iter()
.map(|mut p| p.offset(&Pos::of(1, 0)))
.inspect(|p| println!("{:?}", *p))
.collect();
}
Explanation
The key takeaway here is std::mem::take()'s usage. It's doc says:
[It] Replaces dest with the default value of T, returning the previous dest value.
This essentially means that the destination value (here data_in_some_strct) is replaced with a default value (which happens to be an empty set for BTreeSet), and the original value is returned.
We then perform the same operations on the value returned by take() as in the previous explanation above.
As stated above, collect() builds a new BTreeSet for us by inferring its type from self.data_in_some_strct. We then move the newly created BTreeSet to self.data_in_some_strct.
Note: You can replace *p with p.
This is especially valuable and noteworthy for people who will use (or are
already using) Rc<RefCell<T>> or its thread safe variant.
Instead of using map() to mutate the values in-place, thus putting the code at risk of logic error, one should follow the steps above.

How do I write a function that adds an element to a vector, allowing the element to be changed before insertion?

I'm trying to make a simple example involving a vector of structs to learn Rust. All examples of vectors in the Rust literature I've found only use vectors of integers.
I want to write a function aimed at filling a vector, allowing the possibility of the element to be inserted to be changed, I can't figure out what to do. I always got a compiler error[E0308]: mismatched types on
the push method, because elem is a reference to a Point. So
push() needs a Point structure because v is a vector of Point
but if I want to modify elem, I need to pass a (mutable?) reference
What is the right thing to do?
// structure used everywhere in Rust examples
#[derive(Debug)]
struct Point {
x: i16,
y: i16
}
fn add_element(v: &mut Vec<Point>, elem: &Point) {
// modify element
elem.x = 0;
// add element
v.push(elem);
}
// this example is meant to study a vector of structs
fn main() {
// declare 2 points. By default, live on the stack
let origin = Point {x:0, y:0};
println!("origin address\t: {:p}", &origin);
let mut p1 = Point {x:1, y:1};
println!("p1 address\t: {:p}", &p1);
// declare a new vector of structs. Allocation is made in the heap
// declare mutable because we'll add elements to vector
let mut v: Vec<Point> = Vec::new();
// add points
add_element(&mut v, &origin);
add_element(&mut v, &p1);
// change p1
p1.x = 2;
p1.y = 2;
}
Let's read the error messages together:
error[E0308]: mismatched types
--> src/main.rs:10:12
|
10 | v.push(elem);
| ^^^^ expected struct `Point`, found &Point
|
= note: expected type `Point`
= note: found type `&Point`
The code is attempting to store a reference to a Point in a Vec that is declared to hold entire Points. Since Rust is a statically- and strongly- typed language, the compiler tells you that you cannot do that. The fix is to accept a Point by value:
fn add_element(v: &mut Vec<Point>, elem: Point)
This leads to the next error:
error: cannot assign to immutable field `elem.x`
--> src/main.rs:9:5
|
9 | elem.x = 0;
| ^^^^^^^^^^
You cannot change members of elem because it is not marked as mutable. Mutability of a value is a property of the binding, so let's do that:
fn add_element(v: &mut Vec<Point>, mut elem: Point)
Then change the calling of that function to adapt:
fn main() {
let origin = Point { x: 0, y: 0 };
let p1 = Point { x: 1, y: 1 };
let mut v = Vec::new();
add_element(&mut v, origin);
add_element(&mut v, p1);
}
Note that neither origin nor p1 need to be mutable because this function doesn't modify either while it owns it. It transfers ownership to add_element, which chooses to make it mutable.
but if I want to modify elem, I need to pass a (mutable?) reference
As you can see, you can simply make the elem parameter mutable when transferring the entire value to the function. Since the function owns that value, it has full control over it, including choosing to make it mutable.

Print Vec using a placeholder [duplicate]

I tried the following code:
fn main() {
let v2 = vec![1; 10];
println!("{}", v2);
}
But the compiler complains:
error[E0277]: `std::vec::Vec<{integer}>` doesn't implement `std::fmt::Display`
--> src/main.rs:3:20
|
3 | println!("{}", v2);
| ^^ `std::vec::Vec<{integer}>` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `std::vec::Vec<{integer}>`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required by `std::fmt::Display::fmt`
Does anyone implement this trait for Vec<T>?
let v2 = vec![1; 10];
println!("{:?}", v2);
{} is for strings and other values which can be displayed directly to the user. There's no single way to show a vector to a user.
The {:?} formatter can be used to debug it, and it will look like:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Display is the trait that provides the method behind {}, and Debug is for {:?}
Does anyone implement this trait for Vec<T> ?
No.
And surprisingly, this is a demonstrably correct answer; which is rare since proving the absence of things is usually hard or impossible. So how can we be so certain?
Rust has very strict coherence rules, the impl Trait for Struct can only be done:
either in the same crate as Trait
or in the same crate as Struct
and nowhere else; let's try it:
impl<T> std::fmt::Display for Vec<T> {
fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
Ok(())
}
}
yields:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src/main.rs:1:1
|
1 | impl<T> std::fmt::Display for Vec<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter
Furthermore, to use a trait, it needs to be in scope (and therefore, you need to be linked to its crate), which means that:
you are linked both with the crate of Display and the crate of Vec
neither implement Display for Vec
and therefore leads us to conclude that no one implements Display for Vec.
As a work around, as indicated by Manishearth, you can use the Debug trait, which is invokable via "{:?}" as a format specifier.
If you know the type of the elements that the vector contains, you could make a struct that takes vector as an argument and implement Display for that struct.
use std::fmt::{Display, Formatter, Error};
struct NumVec(Vec<u32>);
impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let mut comma_separated = String::new();
for num in &self.0[0..self.0.len() - 1] {
comma_separated.push_str(&num.to_string());
comma_separated.push_str(", ");
}
comma_separated.push_str(&self.0[self.0.len() - 1].to_string());
write!(f, "{}", comma_separated)
}
}
fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}
Here is a one-liner which should also work for you:
println!("[{}]", v2.iter().fold(String::new(), |acc, &num| acc + &num.to_string() + ", "));
Here is
a runnable example.
In my own case, I was receiving a Vec<&str> from a function call. I did not want to change the function signature to a custom type (for which I could implement the Display trait).
For my one-of case, I was able to turn the display of my Vec into a one-liner which I used with println!() directly as follows:
println!("{}", myStrVec.iter().fold(String::new(), |acc, &arg| acc + arg));
(The lambda can be adapted for use with different data types, or for more concise Display trait implementations.)
Starting with Rust 1.58, there is a slightly more concise way to print a vector (or any other variable). This lets you put the variable you want to print inside the curly braces, instead of needing to put it at the end. For the debug formatting needed to print a vector, you add :? in the braces, like this:
fn main() {
let v2 = vec![1; 10];
println!("{v2:?}");
}
Sometimes you don't want to use something like the accepted answer
let v2 = vec![1; 10];
println!("{:?}", v2);
because you want each element to be displayed using its Display trait, not its Debug trait; however, as noted, you can't implement Display on Vec because of Rust's coherence rules. Instead of implementing a wrapper struct with the Display trait, you can implement a more general solution with a function like this:
use std::fmt;
pub fn iterable_to_str<I, D>(iterable: I) -> String
where
I: IntoIterator<Item = D>,
D: fmt::Display,
{
let mut iterator = iterable.into_iter();
let head = match iterator.next() {
None => return String::from("[]"),
Some(x) => format!("[{}", x),
};
let body = iterator.fold(head, |a, v| format!("{}, {}", a, v));
format!("{}]", body)
}
which doesn't require wrapping your vector in a struct. As long as it implements IntoIterator and the element type implements Display, you can then call:
println!("{}", iterable_to_str(it));
Is there any reason not to write the vector's content item by item w/o former collecting? *)
use std::fmt::{Display, Formatter, Error};
struct NumVec(Vec<u32>);
impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let v = &self.0;
if v.len() == 0 {
return Ok(());
}
for num in &v[0..v.len() - 1] {
if let Err(e) = write!(f, "{}, ", &num.to_string()) {
return Err(e);
}
}
write!(f, "{}", &v[v.len() - 1])
}
}
fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}
*) No there isn't.
Because we want to display something, the Display trait is implemented for sure. So this is correct Rust because: the Doc says about the ToString trait:
"This trait is automatically implemented for any type which implements the Display trait. As such, ToString shouldn’t be implemented directly: Display should be implemented instead, and you get the ToString implementation for free."
In particular on microcontrollers where space is limited I definitely would go with this solution and write immediately.

Resources