generics - 如何在执行动态调度的 Rust 中实现泛型函数?

标签 generics rust dynamic-dispatch

在我正在处理的项目中有这个对象:

enum ContainedType {
    SomeType,
    OtherType,
    ...
}
struct OurObject {
    contains: ContainedType,
    ...
}

impl OurObject {
    pub fn unpack_sometype(self) -> AType { ... }
    pub fn unpack_othertype(self) -> BType { ... }
    ...
}

OurObject是以某种方式“打包”的东西的容器。 每个可以打包的东西都实现了不同的特性。

我们以重复的代码结束,例如:

match foo.type() {
    SomeType => action(foo.unpack_sometype()),
    OtherType => action(foo.unpack_othertype()),
    ...
}

我想分解出 match将代码写入函数中,以便我们可以分派(dispatch)任意特征。

action(foo)

但是,我遇到了问题......

pub fn dispatch<T>(obj: OurObject) -> Box<T> {
    match obj.type() {
        SomeType => Box::new(obj.unpack_sometype()),
        OtherType => Box::new(obj.unpack_othertype()),
        ...
    }
}

T这里应该代表任意特征,如 DebugSomeLocalTrait .

我也尝试过使用像 Box::<T>::new() 这样的涡轮鱼但无济于事。编译器提示 T不会告诉编译器它只是一个特征。有 ?Sized但我找不到 ?IAmTrait .新的 Rust 2018 impl Trait语法以类似的方式失败。

我现在通过使用宏创建函数来解决这个问题。所以我有 dispatch_debugdispatch_cool_trait .本质上是重新实现泛型接口(interface)。因为我们想将它用于不相关的特征,所以我不能使用某种形式的父特征。 DebugDisplay与我们创造的任何特征无关。

有没有更好的方法?在一个完美的世界中,我们会有一个 dispatch允许我们说的函数或方法:

action(foo.dispatch<SomeTrait>())

这是一个沙箱,显示了启动对话的简化版本。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7b739ab11da15ec793ee46c2d8ac47fc

最佳答案

如果你愿意摆脱枚举,你可以使用额外的特征来调度:

trait ObjectTrait {
    fn example1(&self);
    fn example2(&self);
}

struct Object2<E> {
    thing: E,
}

impl<E: fmt::Debug + MeaninglessNumeric> ObjectTrait for Object2<E> {
    fn example1(&self) {
        println!("{:?}", self.thing);
    }
    fn example2(&self) {
        println!("{}", self.thing.numeric());
    }
}

fn example3(o: &ObjectTrait) {
    o.example1();
}
fn example4(o: &ObjectTrait) {
    o.example2();
}

之后你可以调整你的主要:

fn main() {
    let obj1 = OurObject {
        contains: ContainedType::SomeType,
    };
    let obj2 = OurObject {
        contains: ContainedType::OtherType,
    };
    let obj3 = Object2 {
        thing: AType { value: 5 },
    };
    let obj4 = Object2 {
        thing: BType {
            contents: "Hello, World".to_string(),
        },
    };

    example1(obj1);
    example2(obj2);
    example3(&obj3);
    example4(&obj4);
}

Full playground example

关于generics - 如何在执行动态调度的 Rust 中实现泛型函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53784370/

相关文章:

括号内与括号外的 Java 泛型方法参数类型

java - 创建类型为 "Class"的参数化类型

macos - 无法构建 sciter-rs 示例,-lsciter-osx-64 未找到

oop - 多次调度 : A conceptual necessity?

generics - trait 不能做成一个对象

c# - 不明确的 IQueryable<T>.Where 和 IEnumerable<T>.Where 扩展方法

java - 向使用泛型扩展父级的子级添加更多泛型类型

error-handling - 为什么 fs::read_dir() 在 Result<DirEntry, Error> 上返回一个迭代器

rust - 当变量和函数具有相同的名称时,如何调用函数?

rust - Rust 中的动态调度替代方案