去“继承” - 在结构中使用匿名类型作为方法参数

时间:2014-02-03 12:29:50

标签: inheritance go

我正在努力巩固Go提供的遗传概念(可能是“组合”而不是纯粹的遗传)。但是,我无法理解为什么我不能使用“父”类型作为func参数来生成一个作用于参数的泛型函数。

package main

import "log"

type Animal struct {
    Colour string
    Name string
}

type Dog struct {
    Animal
}

func PrintColour(a *Animal) {
    log.Printf("%s\n", a.Colour)
}


func main () {
    a := new (Animal)
    a.Colour = "Void"
    d := new (Dog)
    d.Colour = "Black"

    PrintColour(a)
    PrintColour(d)
}

假设我的理解不正确,我怎样才能在Go中实现我想要的东西?

修改 注意:

  • 我不想将行为附加到struct

  • 我想将指针类型保留为方法参数,因为我在宠物项目上单独工作,这需要我操纵传入的结构然后再对其进行操作。

  • 实际上我的Dog结构将有其他字段/成员;希望这不会使水进一步混乱

5 个答案:

答案 0 :(得分:13)

到目前为止,我喜欢这里的答案,我想添加一个允许您使用接口传递的接口上进行静态类型检查的内容:

package main

import (
    "fmt"
)

type Animalizer interface {
    GetColour() string
}

type Animal struct {
    Colour string
    Name   string
}

type Dog struct {
    Animal
}

func (a *Animal) GetColour() string {
    return a.Colour
}

func PrintColour(a Animalizer) {
    fmt.Print(a.GetColour())
}

func main() {
    a := new(Animal)
    a.Colour = "Void"
    d := new(Dog)
    d.Colour = "Black"

    PrintColour(a)
    PrintColour(d)
}

On the playground

可以向Dog添加更多字段。与Uriel的答案不同的是,如果传入实现PrintColour的结构之外的其他内容,则在编译时对Animalizer的调用将失败。

此外,您不必使用typeswitch,因为编译器知道Animalizer正在实施GetColour

最后,行为(打印)与结构分开,GetColour只返回颜色。

答案 1 :(得分:4)

如果您在PrintColour类型上声明Animal方法,那么当您在Animal中加入Dog时,该方法将被“继承”。

这在Go世界中被称为“嵌入”。有关详细信息,请参阅The "Embedding" section of Effective Go

尝试类似:

package main

import "log"

type Animal struct {
    Colour string
    Name string
}

type Dog struct {
    Animal
}

func (a *Animal) PrintColour() {
    log.Printf("%s\n", a.Colour)
}


func main () {
    a := new (Animal)
    a.Colour = "Void"
    d := new (Dog)
    d.Colour = "Black"

    a.PrintColour()
    d.PrintColour()
}

产地:

  

2009/11/10 23:00:00无效
  2009/11/10 23:00:00黑色

Playground

答案 2 :(得分:3)

您可以使用interface{}

进行尝试
package main

import ("fmt"
       "reflect")

type Animal struct {
    Colour string
    Name string
}

type Dog struct {
    Animal
}

func PrintColour(a interface{}) {
    switch a.(type){
        case *Dog:
            fmt.Printf("Dog %s\n", a.(*Dog).Colour)
        case *Animal:
            fmt.Printf("Aimal %s\n", a.(*Animal).Colour)
        default:        
            fmt.Printf("hmm %s\n", reflect.TypeOf(a))

    }
}


func main () {
    a := new (Animal)
    a.Colour = "Void"
    d := new (Dog)
    d.Colour = "Black"

    PrintColour(a)
    PrintColour(d)

}

答案 3 :(得分:1)

仍然可以使用typename:

显式访问嵌入式(匿名)字段
package main

import "log"

type Animal struct {
    Colour string
    Name   string
}

type Dog struct {
    Animal
}

func PrintColour(a *Animal) {
    log.Printf("%s\n", a.Colour)
}

func main() {
    a := new(Animal)
    a.Colour = "Void"
    PrintColour(a)

    d := new(Dog)
    d.Colour = "Black"
    // you can access the underlying "Animal" through "d.Animal"
    PrintColour(&d.Animal)
}

playground

In the reference:第二个代码块之后的句子解释了如何声明“匿名”字段,并声明:

  

非限定类型名称充当字段名称。

答案 4 :(得分:1)

我的例子可能不太好,但你可以这样做你想做的事情:

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

基本上使用一个接口来定义您希望为所有类型和嵌入类型公开的外部世界的通用功能。

(我的例子可能不是最好但是有效)