我怎样才能避免动态调度?

时间:2018-03-12 02:18:13

标签: rust

我有以下特点:

struct ArtistInfo {
    // some fields
}

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

我希望在不同情况下可以使用几种不同的取件器。我的第一直觉是到达地图并使用特征对象:

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

这将允许我在运行时配置可用的音乐服务集。

这将导致我的Fetcher每个动态调度。我猜测这种鸭子打字是一种非常面向对象的方式来解决手头的问题。是否有可能采用不同的方法来避免动态调度?

1 个答案:

答案 0 :(得分:5)

如果您事先知道您将使用的Fetcher的所有类型,则可以为每种类型定义包含变体的enum

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

然后,您可以使用Box<Fetcher>而不是AnyFetcher。您必须在枚举上match自己进行调度,但是您将调度静态已知的方法,因此这样做的好处是CPU可以看到目的地函数调用(与真正的动态调用相反)。

// 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
        }
    }
}

如果你采用这种方法,你可能会发现Fetcher特征在这一点上实际上没有用处; fetch也可以是每种抓取器类型的固有方法。