rust 如何避免动态分派?

tv6aics1  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(61)

我有以下特点:

struct ArtistInfo {
    // some fields
}

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

字符串
我想有几个不同的提取器,我可以在不同的情况下使用。我的第一个本能是找到一个map并像这样使用trait对象:

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


这将允许我在运行时配置一组可用的音乐服务。
这将导致对每个Fetcher进行动态分派。我冒昧地猜测,这种鸭子类型是处理手头问题的一种非常面向对象的方法。是否有可能避免动态分派的不同方法?

tquggr8v

tquggr8v1#

如果您事先知道要使用的所有Fetcher类型,则可以定义一个enum,其中包含每种类型的变体。

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

字符串
然后,您可以使用AnyFetcher而不是Box<Fetcher>。你必须在enum上使用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 trait在这一点上实际上没有任何用途; fetch也可以是每个提取器类型的固有方法。

相关问题