Reputation: 15702
I'm trying to implement a recursive enum for something like a parse tree. Currently my starting point looks like this:
#[derive(Debug)]
enum Value<T: Add + Copy> {
Sum(Rc<Value<T>>, Rc<Value<T>>),
Scalar(T)
}
Obviously I only care about addition for now and will add other operations later. I want to implement the Add
trait to enable the following:
let x = Value<f32>::Scalar(0.3);
let y = Value<f32>::Scalar(0.3);
let z = x + y;
z
should now be a Value<f32>::Sum
and x
and y
should not be moved. My question is how to implement the Add
trait. Or rather for which types. My first approach looked like this:
impl<T: Add + Copy> Add for crate::Value<T> {
type Output = Self;
fn add(self, other: Value<T>) -> Self {
...
}
}
This solution compiles, but the data is moved. If I try to change the parameters of the add
method to references, it fails because the signature does not match the expected one. Makes sense, so I tried to implement the trait for &Value<T>
. That seems to work, but I cannot write x + y
anymore, because they are not references. I also struggled with the return type, because it cannot be &Value<T>
but must be Value<T>
.
I took another approach to completely work with Rc<Value<T>>
but I'm not allowed to implement Add
for Rc<...>
. I'm aware that there is a AsRef
trait, but I'm quite new to Rust and have now idea how it would fit into my use case.
Any hint how to put those pieces together and get them working would be very appreciated.
Upvotes: 2
Views: 971
Reputation: 42708
You were almost there, you could keep your approach with Rc
but wrap it in your own type:
use std::rc::Rc;
use std::ops::Add;
#[derive(Debug, Clone)]
struct WrapperValue<T: Add + Copy>(Rc<Value<T>>);
#[derive(Debug)]
enum Value<T: Add + Copy> {
Sum(WrapperValue<T>, WrapperValue<T>),
Scalar(T)
}
impl<T: Add + Copy> Add for WrapperValue<T> {
type Output = WrapperValue<T>;
fn add(self, other: WrapperValue<T>) -> Self {
WrapperValue(Rc::new(Value::Sum(self.clone(), other.clone())))
}
}
As you mentioned you dont want to move the value, you can also implement it for &
:
impl<T: Add + Copy> Add for &WrapperValue<T> {
type Output = WrapperValue<T>;
fn add(self, other: &WrapperValue<T>) -> Self::Output {
WrapperValue(Rc::new(Value::Sum(self.clone(), other.clone())))
}
}
Upvotes: 1