Polymorphism in Go lang
Asked Answered
F

5

19

I am learning go lang and i was wondering if there is a way to do something like this:

type Foo struct {
   ...
}

type Bar struct {
   Foo
   ...
}

func getFoo() Foo {
   return Bar{...}
}

In an object oriented language, such code should work without problems, but in go it throws me an error, saying that getFoo() must return an instance of class Foo.

Is there a way to do polymorphism similar to what i've described in Go?

Fisken answered 31/1, 2016 at 15:11 Comment(1)
I think you could Create and return an interface gobyexample.com/interfacesMeteoritics
L
21

Go is not a typical OO language. Also each language has it own way of doing things. You can use interface and composition to achieve what you desire to, as shown below:

package main

import "fmt"

type Foo interface {
   printFoo()
}

type FooImpl struct {

}

type Bar struct {
   FooImpl
}

type Bar2 struct {
   FooImpl
}

func (f FooImpl)printFoo(){
    fmt.Println("Print Foo Impl")
}

func getFoo() Foo {
   return Bar{}
}

func main() {
    fmt.Println("Hello, playground")
    b := getFoo()
    b.printFoo()
}

http://play.golang.org/p/iR8QkD3DnP

Lala answered 31/1, 2016 at 15:39 Comment(3)
I've heard the problem with interface is that it loses compile time type checking, right?Sufferance
I think you're confusing "interface" with "interface {}".. Go will still type check interfaces at compile time, it'll just check that the variable is an instance of that interface. The problem with "interface{}" is that, since the functions that need to be matched for the interface is the empty set, everything matches it, and you lose compile time type checking.Gilliangilliard
It appears Bar2 is not needed in this example?Testee
B
6

In Go, polymorphism is achieved by implementing interfaces.

type Being interface {
        somemethod()
}

type Foo struct {}

type Bar struct {
        Foo
}

type Baz struct {
        Foo
}

// `Bar` and `Baz` implement `Being`
func (b *Bar) somemethod() {}
func (b *Baz) somemethod() {}

func getAnyFoo(b *Being) Foo {
   return b.Foo
}

Therefore, anything implements an empty interface.

type Foo struct {}

type Bar struct {
        Foo
}

// Get anything and extract its `Foo` if anything is a Bar
func getAnyFoo(i interface{}) Foo {
        // Normally this would need a type switch to check the type
        mybar := i.(Bar)
        return mybar.Foo
}
Breathtaking answered 1/2, 2016 at 2:31 Comment(0)
D
0

If you know the types to use you could put them to an array list to implement a kind of polymorph instancing:

package main
import (
  "fmt"
  "encoding/json"
)

type  Hans struct{
      Miau string
    }

type  Keule struct {
  Wuff string
}

func (K Keule)ppp() {
  fmt.Printf(K.Wuff)
}

func (K Hans)ppp() {
  fmt.Printf(K.Miau)
}

func (K Keule)TypeInfo() int {
  return 0
}

func (K Hans)TypeInfo() int {
  return 1
}

type Mega interface {
  ppp()
  TypeInfo() int
}


var j_a = `{
  "Kein_Alter": "nix",
  "Miau": "lala",
  "class": 0
}`

var j_b = `{
  "Alter": "nix",
  "Wuff": "lolo",
  "Class": 1
}`

type Class struct {
  Class int
}

func (K *Class)ppp() {
  fmt.Printf("%d", K.Class)
}

func Unmarshal_K(b []byte) (Mega, error) {
  var k Keule
  err := json.Unmarshal([]byte(j_a), &k)
  return k, err
}

func Unmarshal_H(b []byte) (Mega, error) {
  var k Hans
  err := json.Unmarshal([]byte(j_a), &k)
  return k, err
}

var UList = []func(b []byte) (Mega, error) {Unmarshal_H, Unmarshal_K}

func main() {
  var mv Class
  err := json.Unmarshal([]byte(j_a), &mv)
  if err != nil {
    panic(err)
  }
  

  hiho, err := UList[mv.Class]([]byte(j_a))
  if err != nil {
    panic(err)
  }


  hiho.ppp()
}
Distribution answered 7/11, 2021 at 13:7 Comment(0)
V
0

You can use it in the following way. If you give the print function one of the person or secret Agent, it will understand that it came directly from the human interface and run the function inside it.

package main

import "fmt"

type person struct {
    firstName string
    lastName  string
    age       int
}

type secretAgent struct {
    person
    ltk bool
}

type human interface {
    info() string
}

func (p person) info() string {
    return fmt.Sprint("Name:", p.firstName, " Surname:", p.lastName, " Age:", p.age)
}

func (s secretAgent) info() string {
    return fmt.Sprint("Name:", s.firstName, " Surname:", s.lastName, " Age:", s.age, " Ltk:", s.ltk)
}

func print(h human) {
    switch h.(type) {
    case person:
        fmt.Println("person struct:")
        fmt.Println(h.info())
    case secretAgent:
        fmt.Println("secretAgent struct:")
        fmt.Println(h.info())
    }
}

func main() {

    p := person{
        firstName: "Khanbala",
        lastName:  "Reshidov",
        age:       22,
    }

    s := secretAgent{
        person: p,
        ltk:    true,
    }

    //info Method
    fmt.Println(p.info())
    fmt.Println(s.info())

    //polymorphism

    print(p)
    print(s)

    //type
    fmt.Printf("%T\n", p)
    fmt.Printf("%T\n", s)
}
Vlf answered 30/11, 2022 at 13:37 Comment(0)
L
-1
package main

import "fmt"

// declare interface type
type Dog interface {
    Bark()
}

type Dalmatian struct {
    DogType string
}

type Labrador struct {
    DogType string
}

// implement the interface for both structs
func (d Dalmatian) Bark() {
    fmt.Println("Dalmatian barking!!")
}

func (l Labrador) Bark() {
    fmt.Println("Labrador barking!!")
}

// takes a Dog interface as a parameter
func MakeDogBark(d Dog) {
    d.Bark()
}

func main() {
    // create two instances of different structs that implement the Dog interface
    d := Dalmatian{"Jack"}
    l := Labrador{"Max"}

    // pass them to the function that accepts the Dog interface
    MakeDogBark(d) // Dalmatian barking!!
    MakeDogBark(l) // Labrador barking!!
}

polymorphism in golang allows different types of structs(dalmation and labrador) to implement the same interface(Dog) and be passed to the same func (MakeDogbark) that can call the interface method (Bark) on them.

Literality answered 13/10, 2023 at 22:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.