设置用作映射值的不同结构的字段的通用函数

Rod*_*oAP 2 generics dictionary interface go

具有具有共同字段的结构......

type Definition struct {
        Id string
        ...
}
type Requirement struct {
        Id string
        ...
}
type Campaign struct {
        Id string
        ...
}
Run Code Online (Sandbox Code Playgroud)

...我有多个这样的函数:

func fillDefinitionIds(values *map[string]Definition) {           
        for key, value:=range *values { // Repeated code
                value.Id=key            // Repeated code
                (*values)[key]=value    // Repeated code
        }                               // Repeated code
}
func fillRequirementIds(values *map[string]Requirement) {           
        for key, value:=range *values { // Repeated code
                value.Id=key            // Repeated code
                (*values)[key]=value    // Repeated code
        }                               // Repeated code
}
func fillCampaignIds(values *map[string]Campaign) {           
        for key, value:=range *values { // Repeated code
                value.Id=key            // Repeated code
                (*values)[key]=value    // Repeated code
        }                               // Repeated code
}
Run Code Online (Sandbox Code Playgroud)

我想要一个单一的函数,用泛型(或接口,等等)来概括访问,有点......

func fillIds[T Definition|Requirement|Campaign](values *map[string]T) {           
        for key, value:=range *values {
                value.Id=key
                (*values)[key]=value
        }                                
}
Run Code Online (Sandbox Code Playgroud)

当然,这给出了value.Id undefined (type T has no field or method Id). 我已经多次能够克服类似的问题,但这次我找不到解决方案。

如何将这组函数抽象为一个函数?

bla*_*een 8

使用包含公共字段的结构来编写结构,并在该公共类型上定义 setter 方法:

type Base struct {
    Id string
}

func (b *Base) SetId(id string) {
    b.Id = id
}

type Definition struct {
    Base
}
type Requirement struct {
    Base
}
type Campaign struct {
    Base
}
Run Code Online (Sandbox Code Playgroud)

然后将接口约束定义为指针类型的联合,并指定setter方法。您必须执行此操作,因为当前版本的 Go 中不支持泛型字段访问。

type IDer interface {
    *Definition | *Requirement | *Campaign
    SetId(id string)
}

func fillIds[T IDer](values map[string]T) {
    for key, value := range values {
        value.SetId(key)
        values[key] = value
    }
}
Run Code Online (Sandbox Code Playgroud)

示例: https: //go.dev/play/p/fJhyhazyeyc

func main() {
    m1 := map[string]*Definition{"foo": {}, "bar": {}}
    fillIds(m1)
    for _, v := range m1 {
        fmt.Println("m1", v.Id) 
        // foo
        // bar
    }

    m2 := map[string]*Campaign{"abc": {}, "def": {}}
    fillIds(m2)
    for _, v := range m2 {
        fmt.Println("m2", v.Id)
        // abc
        // def
    }
}
Run Code Online (Sandbox Code Playgroud)