In GoLang how can I add a method for a generic struct

Viewed 82

Is there a way to use golang 1.18 generics with struct methods? Ie something like this such that I have a common method SayName for both Foo and Bar:

package main

import (
    "fmt"
)

type Foo struct {
    Name     string
    Number   int
    FooID string
}

type Bar struct {
    Name     string
    Number   int
    BarID string
}

func  [T Foo|Bar](x *T) SayName() {
    fmt.Printf("%d \"%s\"", x.Number, x.Name)
}

func main() {
    foo := Foo{Name: "Name 1", Number: 1, FooID: "Foo123"}
    foo.SayName()

    bar := Bar{Name: "Name 2", Number: 2, BarID: "Bar456"}
    bar.SayName()
}

I know this can be done in other ways using a base type and struct embedding or interfaces on each, but this is just a contrived example to keep things simple.

UPDATE: To make this more clear, what if I have a slightly less contrived example like below. I know about struct embedding and using base interfaces. But in the case below if SayName was defined as func (b *Base) SayName() {... I would get a run time error because the Base type does not have the GetID interface (it would be nil). So I want to pass in a generic which will have this interface on the Foo and Bar instances. Am I missing something?

For instance this code below would all work if I duplicate the SayName function for each type (as seen in the commented out section)

package main

import (
    "fmt"
)

type Base struct {
    Name   string
    Number int
}

type GetIDIface interface {
    GetID() string
}

type Foo struct {
    Base
    GetIDIface
    FooID string
}

func (f *Foo) GetID() string {
    return f.FooID
}

type Bar struct {
    Base
    GetIDIface
    BarID string
}

func (b *Bar) GetID() string {
    return b.BarID
}

func  [T Foo|Bar](x *T) SayName() {
    fmt.Printf("Number %d \"%s\" with ID of %s", x.Number, x.Name, x.GetID())
}

/* THIS WORKS
func (x *Foo) SayName() {
    fmt.Printf("Number %d \"%s\" with ID of %s\n", x.Number, x.Name, x.GetID())
}

func (x *Bar) SayName() {
    fmt.Printf("Number %d \"%s\" with ID of %s\n", x.Number, x.Name, x.GetID())
}*/

func main() {
    foo := Foo{Base: Base{Name: "Name 1", Number: 1}, FooID: "Foo123"}
    foo.SayName()

    bar := Bar{Base: Base{Name: "Name 2", Number: 2}, BarID: "Bar456"}
    bar.SayName()
}
0 Answers
Related