Go语言中的多态性

19

我正在学习 Go 语言,想知道是否有一种方法可以做到这一点:

type Foo struct {
   ...
}

type Bar struct {
   Foo
   ...
}

func getFoo() Foo {
   return Bar{...}
}
在面向对象的语言中,这样的代码应该可以正常工作,但在Go语言中,它会抛出一个错误,指出getFoo()必须返回类Foo的实例。
是否有一种类似于我所描述的在Go中进行多态性操作的方式?

1
我认为你可以创建并返回一个接口 https://gobyexample.com/interfaces - dm03514
5个回答

21

Go并不是一个典型的面向对象语言。此外,每种语言都有其自己的处理方式。您可以使用接口和组合来实现所需的功能,如下所示:

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


1
我听说接口的问题是它失去了编译时类型检查,对吧? - m0meni
8
我认为你把"interface"和"interface {}"混淆了。在Go中,接口仍然会在编译时进行类型检查,只是检查变量是否是该接口的实例。 "interface {}" 的问题在于,由于需要匹配接口的函数为空集,因此任何东西都与之匹配,导致失去编译时类型检查的作用。 - driusan
@driusan 很棒的回复!谢谢。 - m0meni
1
在这个例子中似乎不需要 Bar2 - Jeff Widman

6
在Go语言中,通过实现接口来实现多态性。
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
}

因此,任何东西都可以实现空接口。
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
}

0

你可以这样使用它。如果你给 print 函数一个 person 或 secret Agent,它会理解它来自于人类界面并在其中运行该函数。

包 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)
}

0

如果您知道要使用的类型,可以将它们放入数组列表中以实现一种多态实例化:

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()
}

-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!!
}

在Golang中,多态性允许不同类型的结构体(达尔马提亚犬和拉布拉多犬)实现相同的接口(狗),并传递给同一个函数(MakeDogbark),该函数可以调用它们的接口方法(Bark)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接