我有一个足够通用的函数来遍历地图[字符串]并获取所有键:
i := 0
keys := make([]string, len(input))
for k := range input {
keys[i] = k
i++
}
return keys
我的问题是我想在这里放入两个不同的输入,一个 map[string]MyStruct 和 map[string][][]float64。每当我尝试将 func 的输入作为 map[string]interface{} 时,go 都会抵制我尝试将 map[string]MyStruct 转换为 map[string]interface{} 的所有尝试。有没有一种方法可以做到这一点,而不需要有两个函数,一个使用map[string]MyStruct作为输入,另一个使用map[string][][]float64?此时,map[string] 的内容并不重要,因为我只是想获取它们的所有键以供稍后在代码中使用。这需要是一个被调用的函数;我们正在使用 Sonar,它被设置为拒绝代码重复,所以我不能重复此代码片段。
在下一个 Go 版本为我们带来泛型之前,有多种方法可以应对它。
重复代码
使用代码生成 - 设计一些模板,然后继续构建将为您填充它。
使用
interface{}
作为函数的输入类型,然后使用反射来猜测函数的类型。
我很确定在这种情况下通用代码将比 2 个独立的函数更复杂。
func getKeys(input interface{}) []string {
switch inp := input.(type) {
case map[string]MyStruct:
keys := make([]string, 0, len(inp))
for k := range inp {
keys = append(keys, k)
}
return keys
case map[string][]float64:
...
default:
fmt.Printf("I don't know about type %T!\n", v)
}
您不能使用输入类型
map[string]interface{}
来放置 map[string]string
或 map[string][]string
go 不会将每个值复制到新类型。您可以采用最通用的类型interface{}
然后投射它。
generics
这可以进一步简化:
func getKeys[T any](input map[string]T) []string {
keys := make([]string, 0, len(input))
for k := range input {
keys = append(keys, k)
}
return keys
}
var intMap = map[string]int{"one": 1, "two": 2, "three": 3}
var stringMap = map[string]string{"one": "1", "two": "2", "three": "3"}
var floatMap = map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}
func main() {
fmt.Println(getKeys(intMap))
fmt.Println(getKeys(stringMap))
fmt.Println(getKeys(floatMap))
}