I am trying to implement a "transform" function that takes a non-copy enum value and and modifies it based on a parameter, but some of the parameters do nothing. A simplified example is:
enum NonCopy {
A,
B,
C
}
fn transform(to_transfrom: &mut NonCopy, param: u32) -> () {
*to_transfrom = match param {
// transformations
1 => NonCopy::A,
2 => NonCopy::B,
// retains the value
_ => *to_transfrom
};
}
I know that since the NonCopy doesn't implement the Copy trait the value inside to_transform cannot be moved out, however if param is neither 1 or 2 the value of *to_transform is assigned to itself, so it stays the same and nothing should be moved, but the compiler doesn't recognize that.
How can I achieve such a pattern with an assignment to a match expression?
I know I could instead assign in the match expression, but the non-example version is bigger and I do not want to repeat so much code plus it is quite ugly.
A neat little trick in Rust is that when you break out of an expression (via return, break, etc.), you don't actually need to provide a value for that expression. In this case, you can return from the match arm without providing a value:
enum NonCopy {
A,
B,
C
}
fn transform(to_transfrom: &mut NonCopy, param: u32) -> () {
*to_transfrom = match param {
// transformations
1 => NonCopy::A,
2 => NonCopy::B,
// retains the value
_ => return,
};
}
Related
With something like the vec below Id like to add arbitrary depth to a json object.
let set = vec![vec!["123","apple","orange","999"],vec!["1234","apple"],vec!["12345","apple","orange"]];
Once created the above would look something like:
{"123":{"apple":{"orange":"999"}}, "1234":"apple", "12345":{"apple":"orange"}}
Ive tried recursion, the issue Im running into is that Im having trouble reasoning through it. The wall Ive hit is how do I refer up the chain of values?
Is there a method Im missing here? Surely Im not the only person whos wanted to do this...
I would prefer if at all possible not writing something cumbersome that takes the length of a key set vec and matches creating the nesting ex.:
match keys.len() {
2 => json_obj[keys[0]] = json!(keys[1]),
3 => json_obj[keys[0]][keys[1]] = json!(keys[2]),
4 => json_obj[keys[0]][keys[1]][keys[2]] = json!(keys[3]),
...
_=> ()
}
Any ideas?
You can do this with iteration -- each loop you walk deeper into the structure, and further into the iterator, but the trick is that each step you need to know if there are more elements beyond the final one because the final element needs to be a string instead of an object. We'll do this using a match construct that matches on the next two items in the sequence at once.
We can further generify the function to take "anything that can be turned into an iterator that produces items from which we can obtain a &str". This will accept both an iterator of String or an iterator of &str, for example, or even directly a Vec of either.
use std::borrow::Borrow;
use serde_json::Value;
fn set_path(
mut obj: &mut Value,
path: impl IntoIterator<Item=impl Borrow<str>>
) {
let mut path = path.into_iter();
// Start with nothing in "a" and the first item in "b".
let mut a;
let mut b = path.next();
loop {
// Shift "b" down into "a" and put the next item into "b".
a = b;
b = path.next();
// Move "a" but borrow "b" because we will use it on the next iteration.
match (a, &b) {
(Some(key), Some(_)) => {
// This level is an object, rebind deeper.
obj = &mut obj[key.borrow()];
}
(Some(s), None) => {
// This is the final string in the sequence.
*obj = Value::String(s.borrow().to_owned());
break;
}
// We were given an empty iterator.
(None, _) => { break; }
}
}
}
(Playground)
I am trying to get a value out of a Ref.
The Ref contains an enum (FeelValue) which has a variant (Number) that holds an f64. FeelValue is not Copy and I do not want to clone it. I just want to get a reference to the f64 value so I can perform a comparison with it.
This is what does not work:
pub enum FeelValue {
Number(f64),
Boolean(bool),
String(String),
// ... many other variants
Null
}
let a: std::cell::Ref<FeelValue> = ...;
let b: std::cell::Ref<FeelValue> = ...;
match (a,b) {
(FeelValue::Number(a_number), FeelValue::Number(b_number)) => FeelValue::Boolean(a_number < b_number),
_ => FeelValue::Null
}
I can't do match (*a, *b) because FeelValue is not Copy. I can clone, but I don't want to. (This is the core of a sort routine which already has to clone everything once.)
How do I get that f64 value out of the Ref<FeelValue::Number> ?
In case you are curious why I am using a Ref, it comes from getting a reference to one value in an Rc<RefCell<Vec<T>>>.
You can do match (&*a, &*b).
The * dereferences the Ref<T> into the inner value T and the & just yields a reference to that inner value.
My goal is to move elements out of an owned Vec.
fn f<F>(x: Vec<F>) -> F {
match x.as_slice() {
&[a, b] => a,
_ => panic!(),
}
}
If F is copy, that is no problem as one can simply copy out of the slice. When F is not, slice patterns seem a no-go, as the slice is read only.
Is there such a thing as an "owned slice", or pattern matching on a Vec, to move elements out of x?
Edit: I now see that this code has the more general problem. The function
fn f<T>(x: Vec<T>) -> T {
x[0]
}
leaves "a hole in a Vec", even though it is dropped right after. This is not allowed. This post and this discussion describe that problem.
That leads to the updated question: How can a Vec<T> be properly consumed to do pattern matching?
If you insist on pattern matching, you could do this:
fn f<F>(x: Vec<F>) -> F {
let mut it = x.into_iter();
match (it.next(), it.next(), it.next()) {
(Some(x0), Some(_x1), None) => x0,
_ => panic!(),
}
}
However, if you just want to retrieve the first element of a 2-element vector (panicking in other cases), I guess I'd rather go with this:
fn f<F>(x: Vec<F>) -> F {
assert_eq!(x.len(), 2);
x.into_iter().next().unwrap()
}
You can't use pattern matching with slice patterns in this scenario.
As you have correctly mentioned in your question edits, moving a value out of a Vec leaves it with uninitialized memory. This could then cause Undefined Behaviour when the Vec is subsequently dropped, because its Drop implementation needs to free the heap memory, and possibly drop each element.
There is currently no way to express that your type parameter F does not have a Drop implementation or that it is safe for it to be coerced from uninitialized memory.
You pretty much have to forget the idea of using a slice pattern and write it more explicitly:
fn f<F>(mut x: Vec<F>) -> F {
x.drain(..).next().unwrap()
}
If you are dead set on pattern matching, you can use Itertools::tuples() to match on tuples instead:
use itertools::Itertools; // 0.9.0
fn f<F>(mut x: Vec<F>) -> F {
match x.drain(..).tuples().next() {
Some((a, _)) => a,
None => panic!()
}
}
One way to achieve consuming a single element of a vector is to swap the last element with the element you want to consume, and then pop the last element
fn f<F>(mut x: Vec<F>) -> F {
match x.as_slice() {
[_a, _b] => {
x.swap(0, 1);
x.pop().unwrap() // returns a
},
_ => panic!(),
}
}
The code uses an unwrap which isn't elegant.
I have the following:
enum SomeType {
VariantA(String),
VariantB(String, i32),
}
fn transform(x: SomeType) -> SomeType {
// very complicated transformation, reusing parts of x in order to produce result:
match x {
SomeType::VariantA(s) => SomeType::VariantB(s, 0),
SomeType::VariantB(s, i) => SomeType::VariantB(s, 2 * i),
}
}
fn main() {
let mut data = vec![
SomeType::VariantA("hello".to_string()),
SomeType::VariantA("bye".to_string()),
SomeType::VariantB("asdf".to_string(), 34),
];
}
I would now like to call transform on each element of data and store the resulting value back in data. I could do something like data.into_iter().map(transform).collect(), but this will allocate a new Vec. Is there a way to do this in-place, reusing the allocated memory of data? There once was Vec::map_in_place in Rust but it has been removed some time ago.
As a work-around, I've added a Dummy variant to SomeType and then do the following:
for x in &mut data {
let original = ::std::mem::replace(x, SomeType::Dummy);
*x = transform(original);
}
This does not feel right, and I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop. Is there a better way of doing this?
Your first problem is not map, it's transform.
transform takes ownership of its argument, while Vec has ownership of its arguments. Either one has to give, and poking a hole in the Vec would be a bad idea: what if transform panics?
The best fix, thus, is to change the signature of transform to:
fn transform(x: &mut SomeType) { ... }
then you can just do:
for x in &mut data { transform(x) }
Other solutions will be clunky, as they will need to deal with the fact that transform might panic.
No, it is not possible in general because the size of each element might change as the mapping is performed (fn transform(u8) -> u32).
Even when the sizes are the same, it's non-trivial.
In this case, you don't need to create a Dummy variant because creating an empty String is cheap; only 3 pointer-sized values and no heap allocation:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
let old = std::mem::replace(self, VariantA(String::new()));
// Note this line for the detailed explanation
*self = match old {
VariantA(s) => VariantB(s, 0),
VariantB(s, i) => VariantB(s, 2 * i),
};
}
}
for x in &mut data {
x.transform();
}
An alternate implementation that just replaces the String:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
*self = match self {
VariantA(s) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 0)
}
VariantB(s, i) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 2 * *i)
}
};
}
}
In general, yes, you have to create some dummy value to do this generically and with safe code. Many times, you can wrap your whole element in Option and call Option::take to achieve the same effect .
See also:
Change enum variant while moving the field to the new variant
Why is it so complicated?
See this proposed and now-closed RFC for lots of related discussion. My understanding of that RFC (and the complexities behind it) is that there's an time period where your value would have an undefined value, which is not safe. If a panic were to happen at that exact second, then when your value is dropped, you might trigger undefined behavior, a bad thing.
If your code were to panic at the commented line, then the value of self is a concrete, known value. If it were some unknown value, dropping that string would try to drop that unknown value, and we are back in C. This is the purpose of the Dummy value - to always have a known-good value stored.
You even hinted at this (emphasis mine):
I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop
That "should" is the problem. During a panic, that dummy value is visible.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
Temporarily move out of borrowed content
How do I move out of a struct field that is an Option?
The now-removed implementation of Vec::map_in_place spans almost 175 lines of code, most of having to deal with unsafe code and reasoning why it is actually safe! Some crates have re-implemented this concept and attempted to make it safe; you can see an example in Sebastian Redl's answer.
You can write a map_in_place in terms of the take_mut or replace_with crates:
fn map_in_place<T, F>(v: &mut [T], f: F)
where
F: Fn(T) -> T,
{
for e in v {
take_mut::take(e, f);
}
}
However, if this panics in the supplied function, the program aborts completely; you cannot recover from the panic.
Alternatively, you could supply a placeholder element that sits in the empty spot while the inner function executes:
use std::mem;
fn map_in_place_with_placeholder<T, F>(v: &mut [T], f: F, mut placeholder: T)
where
F: Fn(T) -> T,
{
for e in v {
let mut tmp = mem::replace(e, placeholder);
tmp = f(tmp);
placeholder = mem::replace(e, tmp);
}
}
If this panics, the placeholder you supplied will sit in the panicked slot.
Finally, you could produce the placeholder on-demand; basically replace take_mut::take with take_mut::take_or_recover in the first version.
Sometimes I have to act on information that is expressed in a long sequence, like:
f1(f2(f3).f4(x,f5(y,z))).f6().f7()
(not necessarily that, just any long sequence you don't want to repeat). And I may need to reference that multiple times, with other code in-between. Like this:
fn myfunc(v: &T) -> X {
match v.func(func(v.func().func())).func() {
...
}
.. other stuff ..
match v.func(func(v.func().func())).func() {
...
}
}
The value is not movable, so I cannot assign it to a variable and then reference the variable twice like in other languages, so essentially I find myself writing the same sequence of function calls multiple times. I tried something like this
let x = &( ... )
and then using this
*x
but this didn't work. I suppose I could use a macro, but then it would be recomputed each time (... which isn't too bad as most of the function calls are just sugar for the compiler and type system), but that's the best I have solved this so far. Is there another way?
If the value is not Copy, then you either need to copy it, or pass by reference. E.g. suppose it was computing a value of type T. I suppose the problem you're currently meeting is
fn foo(x: T) { ... }
fn bar(x: T) { ... }
let your_thing = f1(f2(f3).f4(x,f5(y,z))).f6().f7();
foo(your_thing);
bar(your_thing); // error: use of moved value
The correct fix is changing the foo lines to
fn foo(x: &T) { ... }
foo(&your_thing);
or, the foo call to foo(your_thing.clone()) (if T is Clone). You can decide which one is appropriate by thinking about what sort of ownership foo needs of the T: if it needs full ownership (e.g. passing it to different tasks), you should take it by value foo(x: T); on the other hand, if it only needs a view on to the data (i.e. no ownership), then take a reference foo(x: &T).
See also "Moves vs Copy in Rust" for some background on moving and copying. It includes an explanation of why the &(...) + *x solution isn't work: can't move out from behind a reference (although, in this case it will never work, because moving out twice is illegal anyway).
The same reasoning applies for pattern matching: if you only need a reference, you can take a reference into the value of interest via ref. E.g. imagine you're computing an Option<T>.
let x = v.func(func(v.func().func())).func()
match x {
Some(ref y) => { /* y is a &T */ ... }
None => { ... }
}
// the last `match` can move `x`
match x {
Some(y) => { /* y is a T */ ... }
None => { ... }
}
If the first match does need ownership of some parts of x, you can either clone x itself, or only those parts you need after matching with ref.