How to use fold without making the list mutable? - rust

I have provided an example here:
#[derive(Default)]
struct Example {
name: String,
description: String,
}
fn main() {
let lines = vec![
"N: N1",
"D: D1",
"",
"N: N2",
"D: D2",
"",
];
let data = lines.into_iter().fold(Vec::<Example>::new(), |acc, line| {
let mut examples = acc;
match line.chars().collect::<Vec<char>>().as_slice() {
['N', ..] => {
let mut element:Example = Default::default();
element.name = line[2..].into();
examples.push(element);
}
['D', ..] => {
let mut element = examples.pop().unwrap();
element.description = line[2..].into();
examples.push(element);
}
&[_, ..] => {}
&[] => {}
}
return examples;
});
for example in data{
println!("Name: {}, Description: {}", example.name, example.description);
}
}
Playground
Basically, I will be processing a steam of lines (the amount unknown at runtime, I have used an array here for the purpose of the example) and I want to build up a struct with the information and when I reach a given termination point, I start a new struct and add it to the list.
My first attempts at this used an outer most mutable list. I then discovered the fold method which seemed more elegant (IMO) but I still have to make the list mutable inside.
What would be a better way of achieving this and/or how could I remove the need to make the list mutable?

If you always have this same structure (only 2 fields, 3 rows per record), and you can have 2 independent iterators over the data,
it is possible to do a trick:
let names = lines.iter();
let descriptions = lines.iter().skip(1);
let name_desc_pairs = names.zip(descriptions).step_by(3);
let examples = name_desc_pairs.map(parse_example);
Where fn parse_example(lines: (&String, &String)) -> Example would take a pair of (name_line, description_line) strings and construct an Example.
Otherwise if you want arbitrary number of fields, consider that while you iterate over lines, at first you only get a partial example, so some buffering of the partial state is needed. There are no methods for that in the standard Iterator.
There's chunks method in the futures crate if you can use that: stream::iter(lines).chunks(3) spits out vectors of 3 lines, each of which you can parse into an Example.
Without that it's possible to implement your own buffering & parsing Iterator.
The idea is that the iterator state contains a partial example, e.g.:
struct ExampleBuilder {
name: Option<String>,
description: Option<String>,
}
and wraps the original iterator. In its next() method it calls next() of the original iterator a few times, and either adds line data to ExampleBuilder, or when it gets "" separator - converts ExampleBuilder to Example and returns it.

Related

How to sort a vector containing structs?

Lets say I have some code like:
struct GenericStruct {
a: u8,
b: String,
}
fn sort_array(generic_vector: Vec<GenericStruct>) -> Vec<GenericStruct> {
// Some code here to sort a vector.
todo!();
}
fn main() {
let some_words = String::from("Hello Word");
let x = GenericStruct { a: 25, b: some_words };
let some_vector: Vec<GenericStruct> = vec![x];
}
How could I sort vectors based on one part of it, such as sorting by "a", or sorting by the length of "b"?
Two possiblities.
Either implement the Ord trait for your struct, or use the sort_unstable_by_key method.
You'd use the former if, for your generic_struct, there is an obvious and single way to sort them that makes sense not just in your current sorting use case but generally.
You'd use the latter if this sorting scheme is more of a "one off".
somevector.sort_unstable_by_key(|element| element.a)

What is the correct way to pass references?

I have a function that does multiple operations on two vectors. The vectors consist of structs that are later converted to tuples etc....
What I would like is to change the value of a struct in vector 1 by reference, so that the value in vector 1 is equal to the value in vector 2.
When you run the program, you will better see, what I mean.
You'll get the following two output lines:
new_rows after: IndexSet { rows: [IndexRow { is_old_idx: false, hash: "1", value: [], name: "", viewentry_id: "yyy" }] }
old_rows after: IndexSet { rows: [IndexRow { is_old_idx: true, hash: "1", value: [], name: "", viewentry_id: "xxx" }] }
And what I would like is that in new_rows_after.rows.viewentry_id there is also an "xxx". But it still contains the original value "yyy".
At some point I don't seem to pass the reference correctly, but I just can't find the place.
Is there perhaps an experienced Rust expert here who can see where the error might be?
Thanks for your help.
Playground link
If I may say that, your code is pretty messy. I mean, if you want us to help you, you could at least try to make it easier for us to help. One thing that generally helps is: try to reduce the length of your example code. Maybe this can help you to come up with a minimal version of your code in the future: http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
(it is actually about minimal code examples for ICE, but minimizing Rust examples is really a general thing, if you ask me).
Problem
Now, to the actual problem. I don't really understand your full example code, so what I did, I just reduce it from a whooping 194 lines down to 43 lines, just keeping, what I assume, is your actual problem.
Also, I found your variable names rather confusing. I mean, what I understand that your problem is about, is that new should have the value from old but instead new has its old value instead of the new value of old -- seriously, that is just confusing. So, I went with a simple foo and bar, and here we go:
fn main() {
let dummy_foo = vec![IndexRow {
id: "good".to_string(),
}];
let dummy_bar = vec![IndexRow {
id: "bad".to_string(),
}];
let set_foo = IndexSet { rows: dummy_foo };
let mut set_bar = IndexSet { rows: dummy_bar };
// Should copy ids from set_foo to set_bar
copy_ids(&mut set_bar, &set_foo);
// Here set_bar still contains "bad"
println!("set_bar: {:?}", set_bar);
}
#[derive(Debug)]
pub struct IndexRow {
pub id: String,
}
#[derive(Debug)]
pub struct IndexSet {
pub rows: Vec<IndexRow>,
}
/// Copy ids from `src` to `dest`
pub fn copy_ids<'a, 'b>(dest: &'a mut IndexSet, src: &'b IndexSet) {
// Create tuples each with a dest and src entry
let mut tuples: Vec<(&str, &str)> = dest
.rows
.iter()
.zip(src.rows.iter())
.map(|(d, s)| (d.id.as_str(), s.id.as_str()))
.collect();
for t in tuples.iter_mut() {
let (ref mut dest_id, src_id) = t;
// Override dest with src
*dest_id = *src_id;
}
}
playground
Now as I understand it, in this above version, the issue is just that the id in set_bar should be replaced with the id in set_foo, but instead set_bar still contains the old "bad" as it is printed at the end of main.
Solution
Assuming that this in deed the case: the problem is rather simple. You need to actually change the id, which is a String. However, in the tuples variable, you have only immutable (&) strs. Therefore, *dest_id = *src_id just replaces the one reference with another and all that is only stored/modified within tuples. The actual String is never touched, it is not even accessible as such from tuples.
So, what you need to do is: get your self access to a modifiable (&mut) String and then modify that string directly. Here you can either replace the entire string e.g. with *dest_id = src_id.to_string(), or if you want to make sure that you really have a String on the left-hand side, you can call a function on it that only exists on String and not on str like dest_id.replace_range(.., src_id).
So, this version of copy_ids does what it should do:
/// Copy ids from `src` to `dest`
pub fn copy_ids<'a, 'b>(dest: &'a mut IndexSet, src: &'b IndexSet) {
// Create tuples each with a dest and src entry
let tuples: Vec<(&mut String, &str)> = dest
.rows
.iter_mut()
.zip(src.rows.iter())
.map(|(d, s)| (&mut d.id, s.id.as_str()))
.collect();
// Override dest with src
for (dest_id, src_id) in tuples.into_iter() {
// Replace the content of the String
dest_id.replace_range(.., src_id);
}
}
full example on playground

Rust stacked optional in while let

I am really new in rust, and while going through the rustlings exercises I found something I do not fully understand regarding stacked Options.
Given the following code:
let vector = vec![Some(24), None, Some(42)];
let mut iter = vector.iter();
while let Some(Some(number)) = iter.next() {
println!("Number: {}", number);
}
I would expect to see the following output:
Number: 24
Number: 42
But I guess as soon as rust encounters the None, the while loop exits, only printing the 24
What would be the most idiomatic rust code to iterate and unwrap optional values?
The closest that I got would look something like this:
let mut iter = vector.iter();
while let Some(iterNext) = iter.next() {
if let Some(num) = iterNext {
println!("Number: {}", num);
}
}
Or it could also be done by checking the existence in a for loop:
for opt in &vector {
if opt.is_some() {
println!("Number: {}", opt.unwrap());
}
}
Another nice way to write this code is
for num in vector.iter().flatten() {
println!("{}", num);
}
The flatten() method on an iterator treats each item of the iterator as an iterator, and returns an iterator over all these iterators chained together. Option is an iterator that yields one element if it is Some, or none for None, so flatten() is exactly what we want here.
Of course you could also write this using for_each(), but for code with side effects I generally prefer for loops.
I would expect to see the following output: [...]
A while loop that encounters a false condition exits - but that's not specific to Rust, it's just how while loops work.
An idiomatic solution would probably combine your last two snippets:
for opt in &vector {
if let Some(num) = opt {
println!("Number: {}", num);
}
}
Just a simple for loop containing an if let, no unwrapping required.
Another idiomatic variant is to use iterator adapters:
vector
.iter()
.filter_map(|opt| opt.as_ref())
.for_each(|num| println!("{}", num));
Note that here we could use filter(Option::is_some), but then we would be left with options and would have to use unwrap() to get to the values. This is where
filter_map() comes in useful: it filters the Some values (after applying the map function), and at the same time extracts the values inside. opt.as_ref() serves to trivially convert &Option<T>, obtained from iterating a vector of options by reference, to Option<&T> which filter_map expects returned.
Using and_then to filter out the None's and only delivering Some's to the programs working part:
let vector = vec![Some(24), None, Some(42)];
for num in vector.iter() {
num.and_then::<i32, fn(i32) -> Option<i32>>(|n| {
println!("{}", n); // …working part
None
});
}

How to consume and replace a value in an &mut ref [duplicate]

This question already has answers here:
How can I swap in a new value for a field in a mutable reference to a structure?
(2 answers)
Closed 5 years ago.
Sometimes I run into a problem where, due to implementation details that should be invisible to the user, I need to "destroy" a &mut and replace it in-memory. This typically ends up happening in recursive methods or IntoIterator implementations on recursive structures. It typically follows the form of:
fn create_something(self);
pub fn do_something(&mut self) {
// What you want to do
*self = self.create_something();
}
One example that I happened to have in my current project is in a KD Tree I've written, when I "remove" a node, instead of doing logic to rearrange the children, I just destructure the node I need to remove and rebuild it from the values in its subtrees:
// Some recursive checks to identify is this is our node above this
if let Node{point, left, right} = mem::replace(self, Sentinel) {
let points = left.into_iter().chain(right.into_iter()).collect();
(*self) = KDNode::new(points);
Some(point)
} else {
None
}
Another more in-depth example is the IntoIterator for this KDTree, which has to move a curr value out of the iterator, test it, and then replace it:
// temporarily swap self.curr with a dummy value so we can
// move out of it
let tmp = mem::replace(&mut self.curr, (Sentinel,Left));
match tmp {
// If the next node is a Sentinel, that means the
// "real" next node was either the parent, or we're done
(Sentinel,_) => {
if self.stack.is_empty() {
None
} else {
self.curr = self.stack.pop().expect("Could not pop iterator parent stack");
self.next()
}
}
// If the next node is to yield the current node,
// then the next node is it's right child's leftmost
// descendent. We only "load" the right child, and lazily
// evaluate to its left child next iteration.
(Node{box right,point,..},Me) => {
self.curr = (right,Left);
Some(point)
},
// Left is an instruction to lazily find this node's left-most
// non-sentinel child, so we recurse down, pushing the parents on the
// stack as we go, and then say that our next node is our right child.
// If this child doesn't exist, then it will be taken care of by the Sentinel
// case next call.
(curr # Node{..},Left) => {
let mut curr = curr;
let mut left = get_left(&mut curr);
while !left.is_sentinel() {
self.stack.push((curr,Me));
curr = left;
left = get_left(&mut curr);
}
let (right,point) = get_right_point(curr);
self.curr = (right, Left);
Some(point)
}
As you can see, my current method is to just use mem::replace with a dummy value, and then just overwrite the dummy value later. However, I don't like this for several reasons:
In some cases, there's no suitable dummy value. This is especially true if there's no public/easy way to construct a "zero value" for one or more of your struct members (e.g. what if the struct held a MutexGuard?). If the member you need to dummy-replace is in another module (or crate), you may be bound by difficult constraints of its construction that are undesireable when trying to build a dummy type.
The struct may be rather large, in which case doing more moves than is necessary may be undesirable (in practice, this is unlikely to be a big problem, admittedly).
It just "feels" unclean, since the "move" is technically more of an "update". In fact, the simplest example might be something like *self = self.next.do_something() which will still have problems.
In some cases, such as that first remove snippet I showed, you could perhaps more cleanly represent it as a fn do_something(self) -> Self, but in other cases such as the IntoIterator example this can't be done because you're constrained by the trait definition.
Is there any better, cleaner way to do this sort of in-place update?
In any case we'll need assignment, mem::replace, mem::swap, or something like that. Because given a &mut reference to an object there is no way to move this object (or any of it's fields) out without replacing it's memory area with something valid, as long as Rust forbids references to uninitialized memory.
As for dummy values for replacement, you can always make them yourself for any type by using some wrapper type. For example, I often use Option for this purpose, where Some(T) is the value of type T, and None acts as dummy. This is what I mean:
struct Tree<T>(Option<Node<T>>);
enum Node<T> {
Leaf(T),
Children(Vec<Tree<T>>),
}
impl<T> Tree<T> where T: PartialEq {
fn remove(&mut self, value: &T) {
match self.0.take() {
Some(Node::Leaf(ref leaf_value)) if leaf_value == value =>
(),
node # Some(Node::Leaf(..)) =>
*self = Tree(node),
Some(Node::Children(node_children)) => {
let children: Vec<_> =
node_children
.into_iter()
.filter_map(|mut tree| { tree.remove(value); tree.0 })
.map(|node| Tree(Some(node)))
.collect();
if !children.is_empty() {
*self = Tree(Some(Node::Children(children)));
}
},
None =>
panic!("something went wrong"),
}
}
}
playground link

Finding string slices in an array of string slices

I have a large array of statically allocated string slices, defined like so:
const ARR: [&'static str; 50] = [...];
I'm then iterating through the array in what I assume is a normal manner (I'm new to Rust):
for el in ARR.iter() {
if el == target {
return true;
}
}
Unfortunately, I'm getting an error when I try to use eq():
error: the trait `core::cmp::PartialEq<str>` is not implemented for the type `&str`
Is there something in the standard library to compare string slices, or do I have to just iterate through and compare characters myself? And, for that matter, is there a better way to search for an element in an array than what I'm doing?
Thanks!
Here's how you could write your example:
const FRUITS: [&'static str; 3] = ["apple", "banana", "coconut"];
fn is_available(desired: &str) -> bool {
for &el in FRUITS.iter() {
// let () = el; // PROTIP
if el == desired {
return true;
}
}
false
}
See where I assigned el to ()? That's a little trick to see what the type of a variable is at some point. If you uncomment that, you'll get an error like:
error: mismatched types:
expected `&&str`,
found `()`
This lets you know what the types are. The second part is to look at the implementations of PartialEq for str, the important one being:
impl PartialEq<str> for str
So we bind el with a pattern that will automatically dereference it once for us. Then the comparison can take place, as we have a balanced amount of dereferencing to do:
for &el in FRUITS.iter() {
// ^~~ Here
But really, I'd write it like this:
static FRUITS: [&'static str; 3] = ["apple", "banana", "coconut"];
fn main() {
let desired = "apple";
let to_eat = FRUITS.iter().find(|&&f| f == desired);
println!("{:?}", to_eat);
let desired = "durian";
let to_eat = FRUITS.iter().find(|&&f| f == desired);
println!("{:?}", to_eat);
}
static creates an actual shared place in memory for the variable. const acts more like a C #define - the value is inserted everywhere it is used. Since find returns the item, we need it to have some storage that lasts for longer than the one expression.
IteratorExt::find also abstracts the work of finding a matching value (for some condition), and returns an Option denoting success / failure.

Resources