繁体   English   中英

将两个结构之一的列表传递给 function

[英]Pass list of one of two structures to the function

Go 中的新功能,找不到任何直观的方法。

我有这样一段代码

tx = getTx()
for _, record := range tx.a {
    // do a lot with record.Important
}
for _, record := range tx.b {
    // do a lot with record.Important
}
for _, record := range tx.c {
    // do a lot with record.Important
}

以及以下结构:

type Record1 struct {
    // fields of Record1
    Important string
}
type Record2 struct {
    // fields of Record1
    Important string
}
type TX struct {
    a []Record1
    b []Record1
    c []Record2
}

现在逻辑是将每个for逻辑提取到 function 中:

func helper(records) { // Here is the problem
   // do a lot with record.Important
}

问题:

records[]Record1[]Record2类型。 但看起来 Golang 中不存在 Union 类型。 所以我想我可以将[]string传递给helper ,但甚至找不到一种优雅的方法来获得相当于map(lambda r: r.Important, tx.a)的东西。 没有高阶map function,没有list comprehension。 我不相信使用原始for循环来解决这个问题。

跨多种类型进行循环的一种方法是将接口与 generics 一起使用。让每个Record类型为重要字段实现一个 getter 方法。 然后声明一个接口,在其方法集中包含该 getter 方法。 然后,您可以通过将接口声明为其类型参数来使您的helper通用。

func (r Record1) GetImportant() string { return r.Important }
func (r Record2) GetImportant() string { return r.Important }

type ImportantGetter interface {
     GetImporant() string
}

func helper[T ImportantGetter](s []T) {
    for _, v := range s {
        _ = v.GetImportant()
    }
}

除非我误解了你的问题,否则你似乎想从一组记录中提取 X 列中的所有值,然后将这些值作为切片传递给某个 function - 我的假设基于你希望 go有类似map()的东西。

如果你追求的是类型不可知论,你当然可以使用mkopriva建议的接口方法,但你不会摆脱使用for循环 - 列表类型的迭代是惯用语 go 的核心。如果你需要一个映射 function,你将不得不编写一个来执行你想要的映射。

我会注意到你不需要 generics 来做mkopriva建议的事情,你可以只使用一个界面而不用 generics go playground混淆水域:

package main

import "fmt"

type Record1 struct {
    Important string
}

type Record2 struct {
    Important string
}

func (r Record1) GetImportant() string { return r.Important }
func (r Record2) GetImportant() string { return r.Important }

type ImportantGetter interface {
    GetImportant() string
}

func helper(s []ImportantGetter) {
    for _, v := range s {
        fmt.Println(v.GetImportant())
    }
}

func main() {
    records := []ImportantGetter{Record1{Important: "foo"}, Record2{Important: "bar"}}

    helper(records)
}

另一种类型不可知论的方法,以及“我希望所有这些类型都有一个共同的属性”的惯用方法(恕我直言)是使用struct嵌入和类型断言来构建您自己的Map() function go 操场

type CommonFields struct {
    Important string
}

type Record1 struct {
    CommonFields
    FieldSpecificToRecord1 string
}

type Record2 struct {
    CommonFields
    FieldSpecificToRecord2 int
}

func main() {
    r1 := Record1{
        CommonFields{Important: "I'm r1!"},
        "foo",
    }

    r2 := Record2{
        CommonFields{Important: "I'm r2!"},
        5,
    }

    records := []interface{}{r1, r2, "this is not a valid record type"}

    fmt.Println(Map(records))

}

func Map(source []interface{}) []string {
    destination := make([]string, len(source))
    for i, sourceRecord := range source {
        if rr, ok := sourceRecord.(Record1); ok {
            destination[i] = rr.Important
        } else if rr, ok := sourceRecord.(Record2); ok {
            destination[i] = rr.Important
        } else {
            destination[i] = "undefined"
        }
    }
    return destination
}

您可能想让Map()的实现接受一个参数,该参数指定要提取的字段以符合您在其他语言中的内容,或者甚至可能只是传入一个助手 function 来完成大部分特定于类型的值提取.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM