Go中‘map’和‘reduce’可以用泛型实现吗

问题描述 投票:0回答:2

我决定既然泛型已经被引入 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
}
go generics functional-programming
2个回答
2
投票

这可以很容易地完成。您的代码中有错误,尽管就在这里:

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
}

2
投票

您对

range
的使用不正确。从
range
中提取的单个变量将是索引(类型
int
),而不是值(类型
I
,在本例中这只是巧合
int
)。

尝试

for _, thing := range things{...}
© www.soinside.com 2019 - 2024. All rights reserved.