#rust
Вопрос:
Я пытаюсь реализовать рекурсивное перечисление для чего-то вроде дерева синтаксического анализа. В настоящее время моя отправная точка выглядит следующим образом:
#[derive(Debug)]
enum Value<T: Add Copy> {
Sum(Rc<Value<T>>, Rc<Value<T>>),
Scalar(T)
}
Очевидно, что сейчас я забочусь только о добавлении и добавлю другие операции позже. Я хочу реализовать эту Add
особенность, чтобы обеспечить следующее:
let x = Value<f32>::Scalar(0.3);
let y = Value<f32>::Scalar(0.3);
let z = x y;
z
теперь должно быть Value<f32>::Sum
и x
и y
не должно быть перемещено. Мой вопрос в том, как реализовать эту Add
черту. Или, скорее, для каких типов. Мой первый подход выглядел так:
impl<T: Add Copy> Add for crate::Value<T> {
type Output = Self;
fn add(self, other: Value<T>) -> Self {
...
}
}
Это решение компилируется, но данные перемещаются. Если я попытаюсь изменить параметры add
метода на ссылки, это не удастся, потому что подпись не соответствует ожидаемой. Имеет смысл, поэтому я попытался реализовать эту черту для amp;Value<T>
. Кажется, это работает, но я x y
больше не могу писать, потому что это не ссылки. Я также боролся с типом возврата, потому что этого не может быть amp;Value<T>
, но должно быть Value<T>
.
Я выбрал другой подход, чтобы полностью работать с Rc<Value<T>>
ним, но мне не разрешено его реализовывать Add
Rc<...>
. Я знаю, что есть одна AsRef
особенность, но я совсем новичок в Rust и теперь имею представление о том, как она будет вписываться в мой вариант использования.
Любой намек на то, как собрать эти части воедино и заставить их работать, был бы очень признателен.
Ответ №1:
Вы были почти на месте, вы могли бы сохранить свой подход, 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())))
}
}
Как вы упомянули, вы не хотите перемещать значение, вы также можете реализовать его для amp;
:
impl<T: Add Copy> Add for amp;WrapperValue<T> {
type Output = WrapperValue<T>;
fn add(self, other: amp;WrapperValue<T>) -> Self::Output {
WrapperValue(Rc::new(Value::Sum(self.clone(), other.clone())))
}
}
Комментарии:
1. Это компилируется, но если я создам два экземпляра WrapperValue и добавлю их через» «, данные все равно будут перемещены.
2. Но теперь ты должен написать
amp;x amp;y
. Я хотел писатьx y
, а не перемещать данные. Я начинаю сомневаться, что это возможно. Может работать с типами, которые реализуютCopy
, но это невозможноRc
.3. @Achim afaik ты не можешь, это из-за границ самой черты. вам придется выбрать, я думаю 🙁