How can I avoid dynamic dispatch?

落爺英雄遲暮 提交于 2021-02-05 06:42:06

问题


I have the following trait:

struct ArtistInfo {
    // some fields
}

pub trait Fetcher {
    fn fetch(&self, artist: String) -> ArtistInfo;
}

I want to have several different fetchers that I can use under different circumstances. My first instinct is to reach for a map and use trait objects like so:

type MusicService = String;
let fetchers: HashMap<MusicService, Box<Fetcher>> = HashMap::new();

This will allow me to make the set of available music services configurable at run time.

This will result in dynamic dispatch for each of my Fetchers. I'd hazard to guess that this kind of duck typing is a very Object-Oriented way of approaching the problem at hand. Is there potentially a different approach that would avoid the dynamic dispatching?


回答1:


If you know in advance all the types of Fetchers that you'll be using, you can define an enum containing a variant for each type.

pub enum AnyFetcher {
    Fetcher1(Fetcher1),
    Fetcher2(Fetcher2),
    Fetcher3(Fetcher3),
//  ^^^^^^^^ ^^^^^^^^
//      |        |
//      |      name of a struct/enum that implements `Fetcher`
//      |
//    name of the enum variant
}

Then, instead of using Box<Fetcher>, you can use AnyFetcher. You'll have to match on the enum to do the dispatching yourself, but you'll be dispatching to statically known methods, so this has the benefit that the CPU will be able to see the destination of the function call (contrarily to a true dynamic call).

// AnyFetcher doesn't necessarily have to implement Fetcher.
impl Fetcher for AnyFetcher {
    fn fetch(&self, artist: String) -> ArtistInfo {
        match *self {
            AnyFetcher::Fetcher1(ref fetcher) => fetcher.fetch(artist),
            AnyFetcher::Fetcher2(ref fetcher) => fetcher.fetch(artist),
            AnyFetcher::Fetcher3(ref fetcher) => fetcher.fetch(artist),
//                                   ^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^
//                                      |                  |
//                                      |        these are static calls...
//                                      |
//              ...because each fetcher variable has a distinct type,
//              which is the type of a concrete Fetcher implementation
        }
    }
}

If you're going with this approach, you may realize that the Fetcher trait doesn't actually serve a purpose at this point; fetch could just as well be an inherent method on each fetcher type.



来源:https://stackoverflow.com/questions/49227286/how-can-i-avoid-dynamic-dispatch

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!