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

标签 generics rust traits dynamic-typing

我正在研究 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 .很难说这是“正确”的答案,因为这里的选择可能不满足未说明的要求,但它“有效”并且类似于您问题中的代码:

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 bound,适用于大多数数值类型,应该够用了。如果没有,你可以 Clone相反,它更通用但效率可能较低。

如果两个参数可能有不同的类型,那么你将不得不引入另一个类型参数,S , 并约束 T: Add<S, Output = T> .在这一点上,我会再次质疑你在做什么,并建议你可能需要重新考虑你的整体设计,因为这一切都非常 un-Rusty 和令人困惑。

而不是使用 dyn Any ,我强烈建议您考虑支持类型的枚举。代码可能会更容易理解和调试,而且速度也应该更快。

关于generics - 如何在 Rust 中实现任意加运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55097693/

相关文章:

reference - 我什么时候不应该为引用该特征的实现者而实现该特征?

c++ - 如何从 C++ 模板中的方法类型推断类类型?

ios - Swift 3,使用带有闭包的函数扩展 Objective-C 泛型类

Java 泛型 : Multiple Inheritance in Bounded Type Parameters <T extends A & I>

rust - 如何将枚举值与整数匹配?

memory-management - 使用 RefCell 和 Rc 处理循环图中的内存泄漏

rust - Kcov 报告 100% 的 Rust 库,即使一些方法没有被覆盖

ios - -[当我使用 UITraitCollection 变体时,UITextView setAttributedText :] stops working,

enums - Rust-将特征包装在枚举中以用于内存布局和更简单的泛型?

java - 泛型数组和泛型值有什么区别?