在 Go 中实现切片或结构映射的通用过滤器

时间:2021-06-12 14:51:45

标签: go

我有多个带有“DateLastModified”字段的结构,如下所示:

type Thing struct {
  DateLastModified time.Time
  ...
}

type Thing2 struct {
  DateLastModified time.Time
  ...
}

我有每个结构的切片或映射:

things := []Thing{...}
thing2s := []Thing2{...}

//or

things := make(map[string]Thing)
thing2s := make(map[string]Thing2)

我想做的是在 DateLastModified 字段中过滤每个切片或地图。

这很容易以基本方式实现,但我有兴趣了解有关 Go 的更多信息。

我想知道的是:有没有一种方法可以实现该过滤器,以便我可以执行以下操作:

filteredThings := filterSliceOnTime(things, someTimeToFilterOn)
filtered2Things := filterSliceOnTime(thing2s, someTimeToFilterOn)

//or

filteredThings := filterMapOnTime(things, someTimeToFilterOn)
filtered2Things := filterMapOnTime(thing2s, someTimeToFilterOn)

我想弄清楚的是如何减少冗余代码,因为所有这些结构都具有 DateLastModified 字段。

谢谢!

2 个答案:

答案 0 :(得分:5)

Go 没有协方差的概念,因此 filterXOnTime 将无法对切片 []V 或映射 map[K]V 的不同底层 {{1} 的结构进行操作}s.

带接口

您可以做的是声明一个接口 V 来公开公共行为,并让两个结构都实现该接口:

I

此时您可以拥有 type Modifiable interface { GetDateLastModified() time.Time } type Thing struct { DateLastModified time.Time ... } func (t Thing) GetDateLastModified() time.Time { return t.DateLastModified } type Thing2 struct { DateLastModified time.Time ... } func (t Thing2) GetDateLastModified() time.Time { return t.DateLastModified } 的切片和映射,并且您的过滤器函数可以与这些一起工作(接受和返回):

I

为了使用“通用”函数,您必须将 func filterSliceOnTime(modifiables []Modifiable, someTimeToFilterOn time.Time) []Modifiable { var filtered []Modifiable for _, m := range modifiables { if m.GetDateLastModified.After(someTimeToFilterOn) { filtered = append(filtered, m) } } return filtered } 重新映射到 []ThingX,反之亦然,因此这种方法的有效性略有限制。

带有辅助函数

为了减轻上述解决方案的维护麻烦,您可以改用一个对单个项目进行操作的辅助过滤器功能,这样您就不必来回映射复杂类型:

[]Modifiable

Go 1.18 并输入参数

随着 Go 1.18(2022 年初)和泛型的引入,您将能够直接使用切片和映射。您仍然需要声明接口来为类型参数提供适当的约束,并且结构仍然需要实现它。

使用当前的草稿设计,可能看起来像:

func checkOne(v Modifiable, filterOn time.Time) bool {
    return v.GetDateLastModified().After(filterOn)
}

func main() {
    a := make(map[string]Thing, 0)
    a["foo"] = Thing{time.Now()}

    filtered := make(map[string]Thing, 0)
    for k, v := range a {
        if checkOne(v, time.Now().Add(-2*time.Hour)) {
             filtered[k] = v
        }
    }
    
    fmt.Println(filtered) // map[foo:{blah}]
}

Go2 游乐场:https://go2goplay.golang.org/p/FELhv0NSr5A

答案 1 :(得分:0)

您可以提取具有字段 DateLastModified time.TimeisBefore(start)isAfter(end)isBetween(start, end) 等方法的基础结构