Golang base struct to define methods in substructs
Asked Answered
G

1

5

I would like to create a base struct which have to method, I want to use these methods in the substructs. For example:

type Base struct {
  Type string `json:"$type"`
}

func (b Base) GetJSON() ([]byte, error) {
  return json.Marshal(b)
}

func (b Base) SetType(typeStr string) interface{} {
  b.Type = typeStr
  return b
}

In the new struct I want to use it like this:

type Auth struct {
  Base
  Username
  Password
}

and call these methods in the main:

func main() {
  a := Auth{
    Username: "Test",
    Password: "test",
  }
  a = a.SetType("testtype").(Auth) 
  j, _ := a.GetJSON()
}

In the SetType case I got a panic caused by interface{} is not Auth type, it is Base type. In the GetJSON case I got a json about the Type, but only the Type.

Is there any solution for the problem what I want to solve?

Germaine answered 11/8, 2017 at 12:58 Comment(5)
return b.Type = typeStr isn't a valid Go statement. Base isn't going to have Username and Password fields if that's what you're trying to do. There is no inheritance in Go.Subsonic
I would recommend rethinking your design entirely from a Go perspective. Go is not an object-oriented language. It has no inheritance, and no polymorphism beyond interfaces.Mainstay
Yes, I know that, but how the people solve the given problem, I have 359 struct all with the same methods, should I write them to all?Germaine
@Subsonic I fixed itGermaine
@PumpkinSeed: Why does the it need to be based on methods? Most of the time one would create functions that take defined interfaces. Another solution for huge amount of repetitive code is of course code generation.Subsonic
E
8

As mentioned in the comments, embedding is not inheritance but composition, so you'll probably have to either:

  • Re-think your design to use the tools Go has available
  • Resort to extensive hacking to get the results you want

In the particular case you are showing (trying to get GetJSON() to include also the fields of the outer struct, here is a possible way of getting that to work that does not require many changes (just storing a pointer to the outer struct in Base when creating the struct):

package main

import (
    "encoding/json"
    "fmt"
)

type Base struct {
    Type  string      `json:"$type"`
    selfP interface{} // this will store a pointer to the actual sub struct
}

func (b *Base) SetSelfP(p interface{}) {
    b.selfP = p
}

func (b *Base) GetJSON() ([]byte, error) {
    return json.Marshal(b.selfP)
}

func (b *Base) SetType(typeStr string) {
    b.Type = typeStr
}

type Auth struct {
    Base
    Username string
    Password string
}

func main() {
    a := &Auth{
        Username: "Test",
        Password: "test",
    }
    a.SetSelfP(a) // this line does the trick
    a.SetType("testtype")
    j, _ := a.GetJSON()
    fmt.Println(string(j))
}

Playground link: https://play.golang.org/p/npuy6XMk_t

Entice answered 11/8, 2017 at 13:27 Comment(3)
Thanks, that's exactly what I'm looking for.Germaine
Would this solution be considered hacky? It sure does the trick and it helps with code repetition, should one avoid this sort of solution?Waw
@DusanGligoric I'd prefer making the methods into package functions to avoid repetition.Jodi

© 2022 - 2024 — McMap. All rights reserved.