You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中替代HashMap实现高效易用的GamepadState结构体方案问询

解决方案

1. 用固定大小数组替代HashMap重构GamepadState

HashMap的哈希计算、动态内存分配是主要性能瓶颈,换成固定大小数组可以实现O(1)的访问和更新,完全消除HashMap的运行时开销,同时保持原有API的简洁性。

实现步骤:

首先为gilrs::Axis和gilrs::Button枚举实现索引转换,将每个枚举变体映射到唯一的数组索引:

use gilrs::{Axis, Button};

// 为Axis实现索引转换
trait AxisIndex {
    fn index(&self) -> usize;
}

impl AxisIndex for Axis {
    fn index(&self) -> usize {
        match self {
            Axis::LeftStickX => 0,
            Axis::LeftStickY => 1,
            Axis::RightStickX => 2,
            Axis::RightStickY => 3,
            Axis::LeftZ => 4,
            Axis::RightZ => 5,
            Axis::DpadX => 6,
            Axis::DpadY => 7,
            // 若gilrs新增Axis变体,仅需补充对应索引
        }
    }
}

// 为Button实现索引转换
trait ButtonIndex {
    fn index(&self) -> usize;
}

impl ButtonIndex for Button {
    fn index(&self) -> usize {
        match self {
            Button::South => 0,
            Button::East => 1,
            Button::North => 2,
            Button::West => 3,
            Button::LeftTrigger => 4,
            Button::RightTrigger => 5,
            Button::LeftTrigger2 => 6,
            Button::RightTrigger2 => 7,
            Button::Select => 8,
            Button::Start => 9,
            Button::Mode => 10,
            Button::LeftThumb => 11,
            Button::RightThumb => 12,
            Button::DpadUp => 13,
            Button::DpadDown => 14,
            Button::DpadLeft => 15,
            Button::DpadRight => 16,
            // 若gilrs新增Button变体,仅需补充对应索引
        }
    }
}

然后重构GamepadState,用数组存储状态:

#[derive(Default, Clone)]
pub struct GamepadState {
    // 数组长度对应Axis变体总数,默认值0.0
    axes: [f32; 8],
    // 数组长度对应Button变体总数,默认值false
    buttons: [bool; 17],
}

impl GamepadState {
    // 保持原有API不变,上层代码无需修改
    pub fn axis(&self, axis: Axis) -> f32 {
        self.axes[axis.index()]
    }

    pub fn is_pressed(&self, button: Button) -> bool {
        self.buttons[button.index()]
    }
}

最后更新事件处理逻辑,直接通过索引操作数组:

match event {
    gilrs::EventType::AxisChanged(c_axis, value, _) => {
        gamepad_state.axes[c_axis.index()] = value;
    }
    gilrs::EventType::ButtonPressed(c_button, _) => {
        gamepad_state.buttons[c_button.index()] = true;
    }
    gilrs::EventType::ButtonReleased(c_button, _) => {
        gamepad_state.buttons[c_button.index()] = false;
    }
    _ => {}
}

2. 进阶优化:用bitvec压缩按钮状态

如果对内存占用有要求,可使用bitvec库将按钮状态从每个bool占1字节压缩到每个按钮占1位,进一步降低内存开销,同时保持性能:

  1. 添加依赖:bitvec = { version = "1.0", features = ["prelude"] }
  2. 修改GamepadState:
use bitvec::prelude::*;

#[derive(Clone)]
pub struct GamepadState {
    axes: [f32; 8],
    buttons: BitVec,
}

impl Default for GamepadState {
    fn default() -> Self {
        Self {
            axes: [0.0; 8],
            // 初始化对应Button数量的位向量,默认false
            buttons: BitVec::repeat(false, 17),
        }
    }
}

impl GamepadState {
    pub fn is_pressed(&self, button: Button) -> bool {
        self.buttons[button.index()]
    }
}

事件处理时修改为:

gilrs::EventType::ButtonPressed(c_button, _) => {
    gamepad_state.buttons.set(c_button.index(), true);
}
gilrs::EventType::ButtonReleased(c_button, _) => {
    gamepad_state.buttons.set(c_button.index(), false);
}

额外建议:用num_enum简化索引转换

手动编写枚举到索引的匹配逻辑容易出错,推荐用num_enum库自动生成转换代码:

  1. 添加依赖:num_enum = { version = "0.7", features = ["derive"] }
  2. 封装自定义枚举并派生转换 trait:
use num_enum::{IntoPrimitive, TryFromPrimitive};

#[derive(Debug, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(usize)]
enum MyAxis {
    LeftStickX,
    LeftStickY,
    RightStickX,
    RightStickY,
    LeftZ,
    RightZ,
    DpadX,
    DpadY,
}

// 实现从gilrs::Axis到自定义MyAxis的转换
impl From<gilrs::Axis> for MyAxis {
    fn from(axis: gilrs::Axis) -> Self {
        match axis {
            gilrs::Axis::LeftStickX => Self::LeftStickX,
            gilrs::Axis::LeftStickY => Self::LeftStickY,
            // ... 其他变体映射
        }
    }
}

这样可直接用my_axis.into()获取索引,避免手动编写match的繁琐。

内容的提问来源于stack exchange,提问作者Sreyas Sabbani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:34:59