Home > Software engineering >  Golang idiom for passing multiple argument types
Golang idiom for passing multiple argument types

Time:11-03

I am new to learning Go and have a question around defining an argument that could be one of two types. Take the code:

type Thing struct {
  a int
  b int
  c string
  d string
}

type OtherThing struct {
  e int
  f int
  c string
  d string
}

func doSomething(t Thing/OtherThing) error {
  fmt.println(t.d)
  return nil
}

As the structs have no functions I cannot write an interface for them at present. So what is the Go idiomatic thing to do here? Is it just to bolt on a random function to the structs and write an interface or something else?

Thanks for the help...

CodePudding user response:

Declare a interface with the common functionality for the two types. Use the interface type as the argument type.

// Der gets d values.
type Der interface {
  D() string
}

type Thing struct {
  a int
  b int
  c string
  d string
}

func (t Thing) D() string { return t.d }

type OtherThing struct {
  e int
  f int
  c string
  d string
}

func (t OtherThing) D() string { return t.d }


func doSomething(t Der) error {
  fmt.Println(t.D())
  return nil
}

CodePudding user response:

You can give two structs some shared functionality by composing them both from a base struct:

package main

import (
    "fmt"
)

// Der gets d values.
type Der interface {
    D() string
}

type DBase struct {
    d string
}

func (t DBase) D() string { return t.d }

type Thing struct {
    DBase
    a int
    b int
    c string
}

type OtherThing struct {
    DBase
    e int
    f int
    c string
}

func doSomething(t Der) error {
    fmt.Println(t.D())
    return nil
}

func main() {
    doSomething(Thing{DBase: DBase{"hello"}})
    doSomething(OtherThing{DBase: DBase{"world"}})
}

DBase provides the field (d) and satisfies the Der interface the same way for both Thing and OtherThing. It does make the struct literal a little longer to define.

CodePudding user response:

You can use an interface{} argument and the reflect package to access the common field. Many people will say that this approach is not idiomatic.

func doSomething(t interface{}) error {
    d := reflect.ValueOf(t).FieldByName("d").String()
    fmt.Println(d)
    return nil
}

Try an example on the playground.

  • Related