I have source files that contain text CSV lines for many products for a given day. I want to use Rust to collate these files so that I end up with many new destination CSV files, one per product, each containing portions of the lines only specific to that product.
My current solution is to loop over the lines of the source files and use a HashMap<String, String>
to gather the lines for each product. I split each source line and use the element containing the product ID as a key, to obtain an Entry
(occupied or vacant) in my HashMap
. If it is vacant, I initialize the value with a new String
that is allocated up-front with a given capacity, so that I can efficiently append to it thereafter.
// so far, so good (the first CSV item is the product ID)
let mystringval = productmap.entry(splitsource[0].to_owned()).or_insert(String::with_capacity(SOME_CAPACITY));
I then want to append formatted elements of the same source line to this Entry
. There are many examples online, such as
https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.entry
of how to make this work if the HashMap
value is an integer:
// this works if you obtain an Entry from a HashMap containing int vals
*myval += 1;
I haven't figured out how to append more text to the Entry
I obtain from my HashMap<String, String>
using this kind of syntax, and I've done my best to research examples online. There are surprisingly few examples anywhere of manipulating non-numeric entries in Rust data structures.
// using the Entry obtained from my first code snippet above
*mystringval.push_str(sourcePortion.as_str());
Attempting to compile this produces the following error:
error: type `()` cannot be dereferenced
--> coll.rs:102:17
|
102 | *mystringval.push_str(sourcePortion.as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How can I append to a String
inside the Entry
value?
*mystringval.push_str(sourcePortion.as_str());
is parsed as *(mystringval.push_str(sourcePortion.as_str()));
and since String::push_str
returns ()
, you get the () cannot be dereferenced
error.
Using parentheses around the dereference solves the precedence issue:
(*mystringval).push_str(sourcePortion.as_str());
The reason *myval += 1
works is because unary *
has a higher precedence than +=
, which means it's parsed as
(*myval) += 1
Since or_insert
returns &mut V
, you don't need to dereference it before calling its methods. The following also works:
mystringval.push_str(sourcePortion.as_str());