如何在 Rust 中实现任意加运算符?

How to implement arbitrary add operator in Rust?

我正在研究 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()
}

我从编译器那里得到这样的错误:

error: the downcast_ref method cannot be invoked on a trait object

很明显,编译器不知道如何将 Any 转换为 std::ops::Add

那么做这种事情的最佳做法是什么?

It's obvious that the compiler doesn't know how to cast Any to 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。很难说这是 "correct" 答案,因为这里的选择可能不符合未说明的要求,但它 "works" 并且类似于您问题中的代码:

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,我强烈建议您考虑支持类型的枚举。代码可能更容易理解和调试,而且速度应该也更快。