Очевидно, что компилятор не знает, как привести 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
я настоятельно рекомендую вам рассмотреть перечисление поддерживаемых типов. Код, вероятно, будет легче понять и отладить, и он должен быть быстрее.