简体   繁体   English

在不移动数据的情况下为枚举实现 Add trait

[英]Implementing Add trait for an enum without moving data

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:我想实现Add trait 以启用以下功能:

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. z现在应该是Value<f32>::Sum并且xy不应移动。 My question is how to implement the Add trait.我的问题是如何实现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.如果我尝试将add方法的参数更改为引用,则会失败,因为签名与预期的不匹配。 Makes sense, so I tried to implement the trait for &Value<T> .有道理,所以我尝试为&Value<T>实现特征。 That seems to work, but I cannot write x + y anymore, because they are not references.这似乎有效,但我不能再写x + y ,因为它们不是引用。 I also struggled with the return type, because it cannot be &Value<T> but must be Value<T> .我也为返回类型而苦恼,因为它不能是&Value<T>而必须是Value<T>

I took another approach to completely work with Rc<Value<T>> but I'm not allowed to implement Add for Rc<...> .我采取了另一种方法来完全使用Rc<Value<T>>但我不允许为Rc<...>实现Add 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.我知道有一个AsRef特性,但我对 Rust 很AsRef ,现在知道它如何适合我的用例。

Any hint how to put those pieces together and get them working would be very appreciated.任何有关如何将这些部分放在一起并使它们工作的提示将不胜感激。

You were almost there, you could keep your approach with Rc but wrap it in your own type:你快到了,你可以用Rc保持你的方法,但用你自己的类型包装它:

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())))
    }
}

Playground 操场

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())))
    }
}

Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM