0

I have two structs:

type A struct {
    BankCode           string `json:"bankCode"`
    BankName           string `json:"bankName"`
}

And:

type B struct {
    A 
    extra           string `json:" extra"`
}

And two slices:
listsA []A and listsB []B I want to get bankCodes from listA and listB. bankcodes only contains bankcodes. It is a []string

It will be so easy as using two function.

func getBankCodes(data []A) []string {
    res := make([]string, len(data))
    for i := 0; i < len(data); i++ {
        res[i] = data[i].BankCode
    }
    return res
}

func getBankCodes(data []B) []string {
    res := make([]string, len(data))
    for i := 0; i < len(data); i++ {
        res[i] = data[i].BankCode
    }
    return res
}

How to use one common function ?

star zhang
  • 1
  • 1
  • 4

2 Answers2

1

Well the clean solution would be to use an interface, since go doesn't support classic inheritance, so something like []parentclass can't work. Interfaces however can only describe functions not a common field, so you have to implement a Getter (essentially).

// GetBankCoder provides a function that gives the BankCode
type GetBankCoder interface {
    getBankCode() string
}

// implement GetBankCoder for A (and indirectly for B)
func (a A) getBankCode() string {
    return a.BankCode
}

and make your getBankCodes work on that interface type, notice the parameter of the function as well as the statement inside the loop:

func getBankCodes(data []GetBankCoder) []string {  // <-- changed
    res := make([]string, len(data))
    for i := 0; i < len(data); i++ {
        res[i] = data[i].getBankCode()             // <-- changed
    }
    return res        
}

There are other solutions where the function parameter is of interface{} type and then reflection is used to assure you can actually do .BankCode, but I don't like those, as they are not adding more clarity either.

... However, I couldn't get the golang playground to make this work correctly without putting it into a []GetBankCoder var first, before giving it to the function.

banks := make([]GetBankCoder, 0)
banks = append(banks, A{ BankCode: "ABC", BankName: "ABC Bank"})
getBankCodes(banks)
Jakumi
  • 8,043
  • 2
  • 15
  • 32
0

You may use one common function like so:

func BankCodes(data interface{}) []string {
    if reflect.TypeOf(data).Kind() != reflect.Slice {
        panic("err: data is not slice")
    }
    slice := reflect.Indirect(reflect.ValueOf(data))
    res := make([]string, slice.Len())
    for i := 0; i < slice.Len(); i++ {
        a := slice.Index(i).Interface().(BankCoder)
        res[i] = a.Bankcode()
    }
    return res
}

Code (try on The Go Playground):

package main

import (
    "fmt"
    "reflect"
)

func main() {
    bs := []B{B{A{"BC1", "BN"}, "e"}, B{A{"BC2", "BN"}, "e"}}
    strs := BankCodes(bs)
    fmt.Println(strs)

    as := []A{A{"AC1", "BN"}, A{"AC2", "BN"}}
    strs2 := BankCodes(as)
    fmt.Println(strs2)

}

func BankCodes(data interface{}) []string {
    if reflect.TypeOf(data).Kind() != reflect.Slice {
        panic("err: data is not slice")
    }
    slice := reflect.Indirect(reflect.ValueOf(data))
    res := make([]string, slice.Len())
    for i := 0; i < slice.Len(); i++ {
        a := slice.Index(i).Interface().(BankCoder)
        res[i] = a.Bankcode()
    }
    return res
}

type A struct {
    BankCode string `json:"bankCode"`
    BankName string `json:"bankName"`
}

type B struct {
    A
    extra string `json:" extra"`
}
type BankCoder interface {
    Bankcode() string
}

func (a A) Bankcode() string {
    return a.BankCode
}