I'm following an example from a Rust course:
It has the following function, which works fine as long as key
and val
are of type &str
:
fn from(s: &'buf str) -> Self {
let mut data = HashMap::new();
for sub_str in s.split('&') {
let mut key = sub_str;
let mut val = "";
/* ... */
data.entry(key)
.and_modify(|existing: &mut Value| match existing {
Value::Single(prev_val) => {
*existing = Value::Multiple(vec![prev_val, val]);
}
Value::Multiple(vec) => vec.push(val),
})
.or_insert(Value::Single(val));
}
QueryString { data }
}
Now, I have improved that function to URL-decode key
and val
. But this means that they are of type String
now. The HashMap
and Value
were changed to store String
objects instead of &str
slices.
Now I have a problem:
fn from(s: &'buf str) -> Self {
let mut data = HashMap::new();
for sub_str in s.split('&') {
let key: String = create_key();
let key: String = create_val();
data.entry(key)
.and_modify(|existing: &mut Value| match existing {
Value::Single(prev_val) => {
*existing = Value::Multiple(vec![prev_val, val]);
}
Value::Multiple(vec) => vec.push(val),
})
.or_insert(Value::Single(val)); // <-- ERROR: use of moved value: `val`
}
QueryString { data }
}
Why is the value moved, when the closure doesn't use the "move" keyword ???
And, what would be a good way to fix this ???
Using clone()
everywhere fixes the issue, but I have a feeling the clone()
's are redundant:
fn from(s: &'buf str) -> Self {
let mut data = HashMap::new();
for sub_str in s.split('&') {
let key: String = create_key();
let key: String = create_val();
data.entry(key)
.and_modify(|existing: &mut Value| match existing {
Value::Single(prev_val) => {
*existing = Value::Multiple(vec![prev_val, val.clone()]); // <-- NOTE: clone() here!
}
Value::Multiple(vec) => vec.push(val.clone()), // <-- NOTE: clone() here!
})
.or_insert(Value::Single(val));
}
QueryString { data }
}
After all, we do either and_modify()
or or_insert()
, but never both. So "moving" the value into the branch that we actually take should be fine. And a clone()
should not be required. But how do this?
Thanks!