我一直在尝试使用Golang中的接口和结构来实现“继承”,但是我相信自己做错了方法。用一个例子来解释会更容易。
我想创造不同生物的结构。我希望他们拥有GetName()方法:
type LivingThingProvider interface {
GetName() string
}
现在,所有的人都应该有名字和生日。为此,我正在创建一个结构并将接口嵌入其中:
type LivingThing struct {
birthday string
name string
LivingThingProvider
}
我想添加几种对所有生物都相同的方法:
func (this *LivingThing) Initialize() {
this.birthday = time.Now().Format("02.01.2006")
}
func (this LivingThing) GetBirthday() string {
return this.birthday
}
现在,这里是应该“实现” LivingThing的结构:
type Frog struct {
insectsEaten int
LivingThing
}
func (this Frog) GetName() string {
return fmt.Sprintf("%s-the-Frog-proud-eater-of-%d-insects", this.name, this.insectsEaten)
}
type RobotMan struct {
LivingThing
}
func (this RobotMan) GetName() string {
h := sha256.New()
h.Write([]byte(this.birthday))
return fmt.Sprintf("%s-%X", this.name, h.Sum(nil))
}
在主要功能中,我创建了一个青蛙和一个机器人手,并将其添加到一个切片中,然后在其上循环:
func main() {
fr := Frog{}
fr.name = "Dizzy"
fr.insectsEaten = 586
fr.LivingThingProvider = fr
rm := RobotMan{}
rm.name = "Bender"
rm.LivingThingProvider = rm
fr.Initialize()
rm.Initialize()
entities := []LivingThing{fr.LivingThing, rm.LivingThing}
for _, ent := range entities {
fmt.Printf("Hi, I am %s!\n", ent.GetName())
fmt.Printf("I was born on the %s.\n", ent.GetBirthday())
}
}
一切正常,但是如果我从Frog或RobotMan结构中删除GetName()方法,则它将在运行后编译并出现紧急情况:
panic: runtime error: invalid memory address or nil pointer dereference
这是游乐场链接:https://play.golang.org/p/h2VgvdcXJQA
我的问题如下:
1。就Go而言,我做的是“肮脏的”吗?如果是这样,如何以正确的方式做到这一点?
1a。,尤其是,可以将结构本身分配给其嵌入式接口字段(fr.LivingThingProvider = fr)吗?
2。为什么Go编译器不检查Frog和RobotMan是否实现LivingThingProvider接口?
非常感谢您!
答案 0 :(得分:0)
@mkopriva回答了这一问题,应该得到功劳,但看起来像是经典继承程序员需要的一些解释。
接口定义了诸如名称和生日之类的行为(在Go语言中,习惯用法省略了Get)。结构实现这些接口行为。不嵌入它们。
实现一个接口就是您要做的就是“成为”这个接口。又叫鸭型。
当结构T的实现(Bounded a, Enum a) => a
T成为Stringer时。
在这个特定的示例中,我们可以看到为什么在Golang中一个方法的接口和接口嵌入如此常见。
由于RobotMan确实没有生日,所以我认为最好创建三个接口Namer:Int
,Burner:String() string
和
Name() string
结构组合不是继承的替代品,而是重用代码的另一种方式。