Go中如何用泛型适配自定义命名函数类型的映射?
解决Go泛型中命名函数类型与泛型参数不匹配的问题
问题根源
Go语言中,命名函数类型(如T1、T2)和其底层的函数类型(如func(*Thing1))属于不同类型,因此泛型函数do中定义的map[string]func(*T)无法直接接收原模块的map[string]T1或map[string]T2。
可行解决方案
方案1:调用时转换映射类型
利用Go中命名函数类型可直接转换为底层函数类型的特性,在调用do前将原映射转换为泛型函数期望的类型:
func do[T any](in *T, inMap map[string]func(*T)) { for _, val := range inMap { val(in) } } // 调用示例:转换ModThing1为目标类型 converted := make(map[string]func(*mod.Thing1), len(mod.ModThing1)) for k, v := range mod.ModThing1 { converted[k] = func(*mod.Thing1)(v) // 直接类型转换 } do[mod.Thing1](&mod.Thing1{}, converted)
该方案无需修改原模块代码,适合调用场景较少的情况。
方案2:用泛型约束兼容命名函数类型
定义包含近似函数类型的约束,让泛型函数能够接收任意底层类型为func(*T)的命名函数类型:
// 定义约束:匹配所有底层类型为func(*T)的类型 type Handler[T any] interface { ~func(*T) } // 泛型函数新增Handler约束的类型参数 func do[T any, F Handler[T]](in *T, inMap map[string]F) { for _, val := range inMap { val(in) } } // 直接调用,Go 1.19+可自动推断第二个类型参数 do[mod.Thing1](&mod.Thing1{}, mod.ModThing1) // 旧版本需显式指定两个类型参数 // do[mod.Thing1, mod.T1](&mod.Thing1{}, mod.ModThing1)
该方案无需修改原模块,且调用方式更简洁,是最通用的解决方案。
方案3:修改原模块的类型定义(若允许)
如果有权限修改原模块,将T1、T2定义为类型别名而非新类型:
// 原模块中修改类型定义 type T1 = func(t *Thing1) type T2 = func(t *Thing2)
此时T1与func(*Thing1)完全等价,原泛型函数可直接接收ModThing1,无需任何额外处理。
内容的提问来源于stack exchange,提问作者AC.
相关产品推荐
相关产品推荐

