反映嵌入结构的类型

时间:2018-04-19 07:36:22

标签: oop go struct reflection types

我正在按照我在网上找到的教程尝试一些OOP-esque Go。

到目前为止,它非常吸引人(让我想起试图强迫OOP进入ANSI-C)。

然而,只有一件事困扰我,我似乎无法解决。

我如何能够反映嵌入结构的类型名称?

我在网上找到的所有信息都说无法反映嵌入结构,因为嵌入式结构无法直接访问它。

这完全准确吗?如果是这样,解决以下问题的正确方法是什么(下面的代码)?

基本上,程序打印出三个单独动物的名称,然后是括号中嵌入结构的类型名称,然后是相应动物的“声音”。

对于名为“Rover”的狗,我会打印出“Rover(动物):BARK BARK”。

现在,显然,“罗孚(动物)”并不是特别有用。 理想情况下,这应该是“Rover(Dog)”(嵌入结构的类型名称,而不是嵌入式结构)。

这就是我的问题。我怎么能够反映嵌入结构的类型,所以“流浪者(动物)”变成“流浪者(”狗“),”朱利叶斯(动物)“变成”朱利叶斯(猫)“等?

package main

import (
    "fmt"
    "reflect"
)

type Animal struct {
    Name string
    mean bool
}

type AnimalSounder interface {
    MakeNoise()
}

type Dog struct {
    Animal
    BarkStrength int
}

type Cat struct {
    Basics       Animal
    MeowStrength int
}

type Lion struct {
    Basics       Animal
    RoarStrength int
}

func (dog *Dog) MakeNoise() {
    dog.PerformNoise(dog.BarkStrength, "BARK")
}

func (cat *Cat) MakeNoise() {
    cat.Basics.PerformNoise(cat.MeowStrength, "MEOW")
}

func (lion *Lion) MakeNoise() {
    lion.Basics.PerformNoise(lion.RoarStrength, "ROAR!!  ")
}

func MakeSomeNoise(animalSounder AnimalSounder) {
    animalSounder.MakeNoise()
}

func main() {
    myDog := &Dog{
        Animal{
            Name: "Rover", // Name
            mean: false,   // mean
        },
        2, // BarkStrength
    }

    myCat := &Cat{
        Basics: Animal{
            Name: "Julius",
            mean: true,
        },
        MeowStrength: 3,
    }

    wildLion := &Lion{
        Basics: Animal{
            Name: "Aslan",
            mean: true,
        },
        RoarStrength: 5,
    }

    MakeSomeNoise(myDog)
    MakeSomeNoise(myCat)
    MakeSomeNoise(wildLion)
}

func (animal *Animal) PerformNoise(strength int, sound string) {
    if animal.mean == true {
        strength = strength * 5
    }

    fmt.Printf("%s (%s): \n", animal.Name, reflect.ValueOf(animal).Type().Elem().Name())

    for voice := 0; voice < strength; voice++ {
        fmt.Printf("%s ", sound)
    }

    fmt.Println("\n")
}

1 个答案:

答案 0 :(得分:-1)

好的。

然后回答(或者至少尝试)我自己的问题,提供我认为可能是解决这个问题的正确方法(至少是最简单的方法)。

为简洁起见,我改变了

的所有版本
func (cat/dog/lion *Cat/*Dog/*Lion) MakeNoise(){}

func (animal *Cat/*Dog/*Lion) MakeNoise(){}

据我所知,这不应该真正损害可读性,也不会引入任何副作用。

“MakeNoise()”的所有迭代现在只提供第三个参数 这与嵌入struct的Type name作为字符串相同。

“PerformNoise()”接受该参数(“animalType”)并简单地将其附加到输出

fmt.Printf("%s (%s): \n", animal.Name, animalType)

完整的更新代码:

package main

import (
    "fmt"
    "reflect"
)

type Animal struct {
    Name string
    Type string
    mean bool
}

type AnimalSounder interface {
    MakeNoise()
}

type Dog struct {
    Animal
    BarkStrength int
}

type Cat struct {
    Basics       Animal
    MeowStrength int
}

type Lion struct {
    Basics       Animal
    RoarStrength int
}

func (animal *Dog) MakeNoise() {
    animal.PerformNoise(animal.BarkStrength, "BARK", reflect.ValueOf(animal).Type().Elem().Name())
}

func (animal *Cat) MakeNoise() {
    animal.Basics.PerformNoise(animal.MeowStrength, "MEOW", reflect.ValueOf(animal).Type().Elem().Name())
}

func (animal *Lion) MakeNoise() {
    animal.Basics.PerformNoise(animal.RoarStrength, "ROAR!!  ", reflect.ValueOf(animal).Type().Elem().Name())
}

func MakeSomeNoise(animalSounder AnimalSounder) {
    animalSounder.MakeNoise()
}

func main() {
    myDog := &Dog{
        Animal{
            Name: "Rover", // Name
            mean: false,   // mean
        },
        2, // BarkStrength
    }

    myCat := &Cat{
        Basics: Animal{
            Name: "Julius",
            mean: true,
        },
        MeowStrength: 3,
    }

    wildLion := &Lion{
        Basics: Animal{
            Name: "Aslan",
            mean: true,
        },
        RoarStrength: 5,
    }

    MakeSomeNoise(myDog)
    MakeSomeNoise(myCat)
    MakeSomeNoise(wildLion)
}

func (animal *Animal) PerformNoise(strength int, sound string, animalType string) {
    if animal.mean == true {
        strength = strength * 5
    }

    fmt.Printf("%s (%s): \n", animal.Name, animalType)

    for voice := 0; voice < strength; voice++ {
        fmt.Printf("%s ", sound)
    }

    fmt.Println("\n")
}

PS:重新迭代。我不想用这种“假的”OOP方式编写我的所有代码。

它增加了大量不必要的抽象,并且需要对流程进行新的设计考虑。

但是,我认为这是尝试语言基本功能集的好方法。