3

I am trying to have a generic function that can return various multiple child objects. The idea is to be able to return those in a request json body.

The code is as follows

GenericType struct {
    V1 string `json:"v1"`
    V2 string `json:"v2"`
}

SubType struct {
    GenericType
    V3 string `json:"v3"`
}

func TestFunc() GenericType {
    val := SubType{
        GenericType: GenericType{
            V1: "a",
            V2: "b",
        },
        V3: "c",
    }
    return val
}

The error is

cannot use val (type SubType) as type GenericType in return argument

Is it possible to return a descendant struct in a parent pointer without losing the fields of that descendant struct and then return it as a JSON object in response body?

Sakib
  • 1,503
  • 4
  • 26
  • 39
  • Since Go isn't an OOP language, there's no polymorphism. What you could use though are [interfaces](https://gobyexample.com/interfaces) – Havelock Mar 03 '17 at 08:20
  • @Havelock, well it is not true, it has but Go polymorphism is different than polymorphism in C++ http://stackoverflow.com/a/41592747/629685 – I159 Mar 03 '17 at 10:33

3 Answers3

3

You can't use embedding as a substitute for inheritance. You could use interfaces for that though. Something like:

type Generic interface {
    V1() string
    V2() string
}

type parent struct {
    // ...
}

type child struct {
    // ...
}

// parent
func (p *parent) V1() string {
    return "parent V1"
}

func (p *parent) V2() string {
    return "parent V2"
}

// child
func (c *child) V1() string {
    return "child V1"
}

func (c *child) V2() string {
    return "child V2"
}

// further child methods

func NewGeneric() Generic {
    return &parent{}
    // or 
    // return &child{}
}
Havelock
  • 6,913
  • 4
  • 34
  • 42
1

Go does not have inheritance (like C++ or Java), but only composition and interfaces. So your function could return only one type structure (or pointer) or interface. As a first approximation you could think that interface is nearly the same as pure abstract class in C++).

In your case interface is better. And now it depends how rest of the program will work with returned value. If it need to call a few methods (in go we prefer interface with only few method - ideal is one).

Eg.

type GenericType interface {
    getV1() string
    getV2() string
}

But unfortunately - for all object that could be serialized into JSON we don't have any common method (eg. int, string or arrays), therefore we have to use interface with no common method - interface{}.

lofcek
  • 1,165
  • 2
  • 9
  • 18
0

Embedding

Embedding in Go doesn't allow to inherit (since it is not inheritance) attributes. When you are embedding one struct to another you are composing its' methods (not attributes) to a new composition.

Go does not provide the typical, type-driven notion of subclassing, but it does have the ability to “borrow” pieces of an implementation by embedding types within a struct or interface.

Interfaces

Go provides awesome interfaces to implement generic types and type assertion to have access to concrete types and its' attributes.

Plyground:

type generic interface {
    say() string
}

type type1 struct {
    msg string
}

func (t type1) say() string {
    return t.msg
}

type type2 struct{}

func (t type2) say() string {
    return "I'm type 2"
}

func main() {
    t1 := type1{"Hey! I'm type1"}
    t2 := type2{}

    tl := []generic{t1, t2}

    for _, i := range tl {
        switch v := i.(type) {
        case type1:
            fmt.Println(v.say())
            fmt.Println(v.msg)
        case type2:
            fmt.Println(v.say())
            // fmt.Println(v.msg) Uncomment to see that type2 has no msg attribute.
        }
    }
}
I159
  • 29,741
  • 31
  • 97
  • 132