我决定既然泛型已经被引入 Go,像
map/reduce
这样的东西应该是可能的。因此,我天真地尝试了一下,但得到了错误:
./prog.go:18:36: cannot use thing (variable of type int) as type I in argument to mapper
这并不能解释问题是否是根本性的,或者我只是在语法上做错了什么。 Go 中可以实现通用的 Map/Reduce 吗?
package main
import "fmt"
func main() {
things := []int{1, 2, 3, 4}
results := Map(things, func(t int) int {
return t + 1
})
fmt.Printf("%v", results)
}
func Map[I interface{}, O interface{}](things []I, mapper func(thing I) O) []O {
results := make([]O, 0, len(things))
for thing := range things {
results = append(results, mapper(thing))
}
return results
}
这可以很容易地完成。您的代码中有错误,尽管就在这里:
for thing := range things {
您正在迭代索引值 (int),而不是
I
类型的值。您还指定了 2 个约束(类型 I
和 O
),均设置为 interface{}
。您可以直接使用 any
(它是 interface{}
的简写)
所以简单地写:
func Map[T any, O any](things []T, mapper func(thing T) O) []O {
result := make([]O, 0, len(things))
for _, thing := range things {
result = append(result, mapper(thing))
}
return result
}
这与我在代码审查交流这里审查的一些代码密切相关。在浏览完代码并编写带有大量建议的片段后,我决定创建一个包并将其放在 github 上。您可以在此处找到该存储库。
其中有一些示例可能会派上用场,或者帮助您解决 golang 中 WRT 泛型的一些其他问题。我特别考虑了这一点,您可以使用回调来过滤通用地图类型,如下所示:
// given the sMap type
type sMap[K comparable, V any] struct {
mu *sync.RWMutex
m map[K]V
}
// Filter returns a map containing the elements that matched the filter callback argument
func (s *sMap[K, V]) Filter(cb func(K, V) bool) map[K]V {
s.mu.RLock()
defer s.mu.RUnlock()
ret := make(map[K]V, len(s.m))
for k, v := range s.m {
if cb(k, v) {
ret[k] = v
}
}
return ret
}
您对
range
的使用不正确。从 range
中提取的单个变量将是索引(类型 int
),而不是值(类型 I
,在本例中这只是巧合 int
)。
尝试
for _, thing := range things{...}