英文:
Go "inheritance" - using anonymous type in a struct as a method parameter
问题
我正在尝试弄清楚Go提供的继承概念(可能更接近"组合"而不是纯粹的继承)。然而,我无法理解为什么我不能将"父类"类型作为func
参数来生成一个作用于该参数的通用函数。
假设我的理解是错误的,我该如何在Go中实现我想要的效果?
编辑
注意:
-
我不想将行为附加到结构体上。
-
我希望保持指针类型作为方法参数,因为我在一个独立的项目上单独处理结构体,这要求我在对其进行操作之前对其进行修改。
-
实际上,我的
Dog
结构体会有额外的字段/成员;希望这不会进一步混淆问题。
英文:
I'm trying to firm up the concept of inheritence that Go provides (rather "composition" than pure inheritence, perhaps). However, I'm failing to grasp why I can't use the "parent" type as a func
parameter to produce a generic function that acts on the parameter.
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)
}
Assuming my understanding's incorrect, how can I achieve what I want in Go?
Edit
Note:
-
I don't want to attach the behaviour to the struct
-
I'd like to keep the pointer type as the method parameter because I'm working separately on a pet project and this requires I manipulate the struct passed in before then acting on it.
-
In reality my
Dog
struct would have additional fields/members; hopefully this doesn't muddy the water further
答案1
得分: 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)
}
在这个示例中,你可以进一步添加Dog
的字段。与Uriel的答案不同之处在于,如果传入的不是实现了Animalizer
接口的结构体,调用PrintColour
将在编译时失败。
此外,你不需要使用类型断言,因为编译器知道Animalizer
实现了GetColour
方法。
最后,行为(打印)与结构体分离,GetColour
只返回颜色。
英文:
I like the answers here so far and I want to add one that allows you to do static type checking on the interface you pass in using an interface:
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)
}
It will be possible to add further fields to Dog
. The difference to Uriel's Answer is that calls to PrintColour
will fail at compile time if something else than a struct implementing Animalizer
is passed in.
Also you won't have to use a typeswitch since the compiler knows an Animalizer
is implementing GetColour
.
And, finally, the behaviour (printing) is separated from the struct, GetColour
just returns the colour.
答案2
得分: 4
如果你在Animal
类型上声明了PrintColour
方法,当你在Dog
中包含Animal
时,它将被“继承”。
这在Go语言中被称为“嵌入”。详细信息请参阅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 Void
2009/11/10 23:00:00 Black
英文:
If you declare the PrintColour
method on the Animal
type, it will be "inherited" when you include Animal
in Dog
.
This is known as "Embedding" in the Go world. See The "Embedding" section of Effective Go for more info.
Try something like:
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()
}
Produces:
>2009/11/10 23:00:00 Void
2009/11/10 23:00:00 Black
答案3
得分: 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("狗的颜色:%s\n", a.(*Dog).Colour)
case *Animal:
fmt.Printf("动物的颜色:%s\n", a.(*Animal).Colour)
default:
fmt.Printf("嗯,%s\n", reflect.TypeOf(a))
}
}
func main() {
a := new(Animal)
a.Colour = "无色"
d := new(Dog)
d.Colour = "黑色"
PrintColour(a)
PrintColour(d)
}
希望对你有帮助!
英文:
You could try it with 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)
}
答案4
得分: 1
嵌入(匿名)字段仍然可以通过使用其类型名称来显式访问:
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"
// 你可以通过"d.Animal"访问底层的"Animal"
PrintColour(&d.Animal)
}
在参考文档中:第二个代码块之后的句子解释了如何声明一个“匿名”字段,并且说明:
未限定的类型名称充当字段名。
英文:
The embedded (anonymous) field can still be explicitly accessed by using its 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)
}
In the reference : the sentence after the second code block explains how you can declare an "anonymous" field, and states :
> The unqualified type name acts as the field name.
答案5
得分: 1
我的例子可能不是很好,但你可以用这种方式做你想做的事情:
http://play.golang.org/p/JoAlOvJthr
基本上,使用接口来定义你想要对外界公开的所有类型和嵌入类型的共同功能。
(我的例子可能不是最好的,但它可以工作)
英文:
My example might not be great but you can do what you want this way:
http://play.golang.org/p/JoAlOvJthr
Essentially use an interface to define the common functionality you want to expose to the outside world for all your types and embedded types.
(My example may not be the best but it works)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论