Как реализовать произвольный оператор добавления в Rust? - PullRequest
0 голосов
/ 11 марта 2019

Я работаю над произвольным выражением в Rust,

В качестве примера рассмотрим оператор Add:

fn eval_add<T: ?Sized + Add<T, Output=T>>(l: Rc<Any>, r: Rc<Any>) -> Rc<Any> {
    l.downcast_ref::<Add<T, Output=T>>().unwrap() +
    r.downcast_ref::<Add<T, Output=T>>().unwrap()
}

и я получил такую ​​ошибку от компилятора:

ошибка: метод downcast_ref не может быть вызван для объекта признака

Очевидно, что компилятор не знает, как привести Any к std::ops::Add.

Так, как лучше всего делать такие вещи?

1 Ответ

3 голосов
/ 11 марта 2019

Очевидно, что компилятор не знает, как привести Any к std :: ops :: Add.

Это потому, что Add - это черта, и вы можете опускаться только до типа.

Это не работает:

l.downcast_ref::<Add<T, Output=T>>()

Поскольку Add - это черта, это действительно так:

l.downcast_ref::<dyn Add<T, Output=T>>()

То, что вы, вероятно, намеревались, было просто:

l.downcast_ref::<T>()

Поскольку T является переменной типа в области видимости, которая реализует Add.

Ваши требования довольно неясны, и настройка кажется немного странной: вы передаете Rc<dyn Any>, но у вас также есть этот параметр T, который может означать только то, что вызывающий абонент знает конкретный тип этих dyn Any аргументы, для того, чтобы поставить правильные T. Трудно сказать, что это «правильный» ответ, потому что здесь есть варианты, которые могут не соответствовать неустановленным требованиям, но они «работают» и напоминают код в вашем вопросе:

use std::rc::Rc;
use std::any::Any;
use std::ops::Add;

fn eval_add<T>(l: Rc<dyn Any>, r: Rc<dyn Any>) -> Rc<dyn Any> 
where
    T: Add<T, Output = T> + Copy + 'static
{
    let l = *l.downcast_ref::<T>().unwrap();
    let r = *r.downcast_ref::<T>().unwrap();
    Rc::new(l + r)
}

Обратите внимание, что Add::add принимает аргумент по значению, поэтому необходимо скопировать или клонировать его, поскольку он заимствован из Rc. Я добавил границу Copy, которая применяется к большинству числовых типов, которых должно быть достаточно. Если нет, вы могли бы вместо этого Clone, что является более общим, но потенциально менее эффективным.

Если два аргумента могут иметь разные типы, вам придется ввести другой параметр типа, S, и ограничить T: Add<S, Output = T>. В этот момент я бы снова поставил под сомнение то, что вы делаете, и предположил бы, что вам, возможно, придется переосмыслить свой общий дизайн, поскольку все это очень не растерянно и запутанно.

Вместо использования dyn Any я настоятельно рекомендую вам рассмотреть перечисление поддерживаемых типов. Код, вероятно, будет легче понять и отладить, и он должен быть быстрее.

...