如何创建值为函数的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}>`
问题分析
- 函数类型完全不匹配:结构体中
HashMap定义的值类型是fn()->()(无参无返回的普通函数指针),但Self::func1和Self::func2是成员函数,实际类型为fn(&mut A)(需要接收可变self引用作为参数)。 - 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
相关产品推荐
相关产品推荐

