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

如何创建值为函数的HashMap?Rust结构体函数HashMap编译错误修复

Rust结构体中存储成员函数的HashMap类型不匹配问题修复

原代码

use std::collections::HashMap;

struct A{
  pub funcs: HashMap<&'static str, fn()->()>,
  f1:i32,
  f2:i32
}
impl A {
  fn func1(&mut self) {self.f1+=1;println!("func1 has called {} time(s)",self.f1);}
  fn func2(&mut self) {self.f2+=1;println!("func2 has called {} time(s)",self.f2);}
  fn set_funcs(&mut self) {
    self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
  }
}

fn main() {
    let mut a = A{funcs:HashMap::new(),f1:0,f2:0};
    a.set_funcs();
    a.funcs.get("f1").unwrap()();
}

编译错误

error[E0308]: mismatched types
  --> src/main.rs:12:58
   |
12 |     self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
   |                                                          ^^^^^^^^^^^ expected fn item, found a different fn item
   |
   = note: expected fn item `for<'r> fn(&'r mut A) {A::func1}`
              found fn item `for<'r> fn(&'r mut A) {A::func2}`

error[E0308]: mismatched types
  --> src/main.rs:12:18
   |
12 |     self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
   |     ----------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
   |     |
   |     expected due to the type of this binding
   |
   = note: expected struct `HashMap<&'static str, fn()>`
              found struct `HashMap<&str, for<'r> fn(&'r mut A) {A::func1}>`

问题分析

  1. 函数类型完全不匹配:结构体中HashMap定义的值类型是fn()->()(无参无返回的普通函数指针),但Self::func1和Self::func2是成员函数,实际类型为fn(&mut A)(需要接收可变self引用作为参数)。
  2. fn item类型不统一:Rust中每个成员函数都是独立的fn item类型,直接放入数组会被推断为同一fn item(比如A::func1的类型),但A::func2是另一个不同的fn item,导致数组元素类型冲突;需要显式转换为统一的函数指针类型。

修复方案

方案一:用闭包捕获self,存储动态分发的闭包

通过闭包捕获&mut self,用Box<dyn FnMut()>存储可调用对象,调用方式更直观:

use std::collections::HashMap;

struct A {
    pub funcs: HashMap<&'static str, Box<dyn FnMut()>>,
    f1: i32,
    f2: i32,
}

impl A {
    fn func1(&mut self) {
        self.f1 += 1;
        println!("func1 has called {} time(s)", self.f1);
    }

    fn func2(&mut self) {
        self.f2 += 1;
        println!("func2 has called {} time(s)", self.f2);
    }

    fn set_funcs(&mut self) {
        // 用Box包裹闭包,捕获当前实例的可变引用
        self.funcs.insert("f1", Box::new(move || self.func1()));
        self.funcs.insert("f2", Box::new(move || self.func2()));
    }
}

fn main() {
    let mut a = A {
        funcs: HashMap::new(),
        f1: 0,
        f2: 0,
    };
    a.set_funcs();
    // 调用时需要获取可变引用
    a.funcs.get_mut("f1").unwrap()();
    a.funcs.get_mut("f2").unwrap()();
    a.funcs.get_mut("f1").unwrap()();
}

方案二:存储成员函数指针,调用时手动传入self

直接存储成员函数指针类型for<'a> fn(&'a mut A),无额外运行时开销,但调用时需手动传入&mut self:

use std::collections::HashMap;

struct A {
    pub funcs: HashMap<&'static str, for<'a> fn(&'a mut A)>,
    f1: i32,
    f2: i32,
}

impl A {
    fn func1(&mut self) {
        self.f1 += 1;
        println!("func1 has called {} time(s)", self.f1);
    }

    fn func2(&mut self) {
        self.f2 += 1;
        println!("func2 has called {} time(s)", self.f2);
    }

    fn set_funcs(&mut self) {
        // 显式转换为统一的成员函数指针类型
        self.funcs = HashMap::from([
            ("f1", Self::func1 as for<'a> fn(&'a mut A)),
            ("f2", Self::func2 as for<'a> fn(&'a mut A)),
        ]);
    }
}

fn main() {
    let mut a = A {
        funcs: HashMap::new(),
        f1: 0,
        f2: 0,
    };
    a.set_funcs();
    // 调用时传入可变self引用
    let f = a.funcs.get("f1").unwrap();
    f(&mut a);
    let f = a.funcs.get("f2").unwrap();
    f(&mut a);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:35:10