我有以下特点:
struct ArtistInfo {
// some fields
}
pub trait Fetcher {
fn fetch(&self, artist: String) -> ArtistInfo;
}
我想要有几个不同的获取器,可以在不同的情况下使用。我的第一反应是找到一张地图并使用特征对象,如下所示:
type MusicService = String;
let fetchers: HashMap<MusicService, Box<dyn Fetcher>> = HashMap::new();
这将使我能够在运行时配置可用的音乐服务集。
这将导致我的每个Fetcher
s。我大胆猜测这种鸭子类型是解决当前问题的一种非常面向对象的方法。是否有可能采用不同的方法来避免动态调度?
如果您事先知道所有类型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
也可以是每个获取器类型的固有方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)