第一次遇到这种写法,需要记录一下开开眼。
仔细一想,这是很合理的嘛。
普通类型的泛型方法 - 泛型会输出普通类型能处理的数据
/// Maps markers that implement [`InputAction`] to their data (state, value, etc.).
///
/// Stored inside [`Actions`](crate::actions::Actions).
///
/// Accessible from [`InputCondition::evaluate`](crate::input_condition::InputCondition::evaluate)
/// and [`InputModifier::apply`](crate::input_modifier::InputModifier::apply)
#[derive(Default, Deref, DerefMut)]
pub struct ActionMap(pub HashMap<TypeId, Action>);
impl ActionMap {
/// Returns associated state for action `A`.
pub fn action<A: InputAction>(&self) -> Option<&Action> {
self.get(&TypeId::of::<A>())
}
/// Inserts a state for action `A`.
///
/// Returns previously associated state if present.
pub fn insert_action<A: InputAction>(&mut self, action: Action) -> Option<Action> {
self.insert(TypeId::of::<A>(), action)
}
}
普通方法调用自己的泛型方法
泛型,是写法上抽象,编译期就单态化成具体类型了。 所以核心就是:调用泛型方法时能知道具体类型就行。
下面的例子中Action就是普通类型,new和trigger_events_typed方法都是泛型方法,
在new里面设置回调字段,是自己的泛型方法,这里就带上了泛型信息,
在普通方法trigger_events调用回调时,编译器能推导出具体类型信息。
这里的用法非常巧.
pub struct Action {
state: ActionState,
events: ActionEvents,
value: ActionValue,
elapsed_secs: f32,
fired_secs: f32,
trigger_events: fn(&Self, &mut Commands, Entity),
}
impl Action {
/// Creates a new instance associated with action `A`.
///
/// [`Self::trigger_events`] will trigger events for `A`.
#[must_use]
pub fn new<A: InputAction>() -> Self {
Self {
state: Default::default(),
events: ActionEvents::empty(),
value: ActionValue::zero(A::Output::DIM),
elapsed_secs: 0.0,
fired_secs: 0.0,
trigger_events: Self::trigger_events_typed::<A>,
}
}
/// Triggers events resulting from a state transition after [`Self::update`].
///
/// See also [`Self::new`] and [`ActionEvents`].
pub fn trigger_events(&self, commands: &mut Commands, entity: Entity) {
// 这个触发事件的方法可以简写为直接用的,这里加一层是为了给以后做扩展。
// eg:未来可能作为pub,由外部指定。
//
// 还有一个有意思的:当前方法是普通方法,调用的却是泛型方法,
// 这个泛型回调是当前类型Action在new时代入泛型的。
// 所以才能在普通方法中调用泛型方法。
(self.trigger_events)(self, commands, entity);
}
/// A typed version of [`Self::trigger_events`].
fn trigger_events_typed<A: InputAction>(&self, commands: &mut Commands, entity: Entity) {
for (_, event) in self.events.iter_names() {
match event {
ActionEvents::STARTED => {
trigger_and_log::<A, _>(
commands,
entity,
Started::<A> {
value: A::Output::as_output(self.value),
state: self.state,
},
);
}
ActionEvents::ONGOING => {
trigger_and_log::<A, _>(
commands,
entity,
Ongoing::<A> {
value: A::Output::as_output(self.value),
state: self.state,
elapsed_secs: self.elapsed_secs,
},
);
}
ActionEvents::FIRED => {
trigger_and_log::<A, _>(
commands,
entity,
Fired::<A> {
value: A::Output::as_output(self.value),
state: self.state,
fired_secs: self.fired_secs,
elapsed_secs: self.elapsed_secs,
},
);
}
ActionEvents::CANCELED => {
trigger_and_log::<A, _>(
commands,
entity,
Canceled::<A> {
value: A::Output::as_output(self.value),
state: self.state,
elapsed_secs: self.elapsed_secs,
},
);
}
ActionEvents::COMPLETED => {
trigger_and_log::<A, _>(
commands,
entity,
Completed::<A> {
value: A::Output::as_output(self.value),
state: self.state,
fired_secs: self.fired_secs,
elapsed_secs: self.elapsed_secs,
},
);
}
_ => unreachable!("iteration should yield only named flags"),
}
}
}
}
如果不这样, 直接调用泛型方法是否可以?
如果调用方不是泛型函数,或泛型类型和泛型方法不匹配: 不行的。
通过这种初始化保存回调的方法,其实已经将泛型函数单态化了,普通函数都可以调用。