不是泛型类型却有泛型方法

第一次遇到这种写法,需要记录一下开开眼。

仔细一想,这是很合理的嘛。

/// 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就是普通类型,newtrigger_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"),
              }
        }
    }
}

如果调用方不是泛型函数,或泛型类型和泛型方法不匹配: 不行的。

通过这种初始化保存回调的方法,其实已经将泛型函数单态化了,普通函数都可以调用。