Golang结构在方法重载时调用嵌入式类型方法

时间:2013-12-31 18:31:43

标签: go

我正在努力学习Go,我找到了一个很好的资源here

关于方法重载的示例如下:

package main
import "fmt"

type Human struct {
    name string
    age int
    phone string
}


type Employee struct {
    Human 
    company string
}

func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

func (e *Employee) SayHi() {
    fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
        e.company, e.phone) //Yes you can split into 2 lines here.
}

func main() {
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
    sam.SayHi()
}

是否可以调用“基础”结构(人类)方法,例如。 sam.Human.SayHi()向下转换不起作用(因为没有类型层次结构对吗?)

2 个答案:

答案 0 :(得分:67)

您可以通过使用嵌入类型名称的名称调用父成员来访问父结构的嵌入结构。这是一个满口的,所以展示它可能更容易。

 sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
 sam.SayHi() // calls Employee.SayHi
 sam.Human.SayHi() // calls Human.SayHi

输出

 Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX
 Hi, I am Sam you can call me on 111-888-XXXX

答案 1 :(得分:0)

这是迄今为止我发现的最接近具有普通和纯虚函数的理智多态性的近似值。根据 Go 设计的本质和手头的目标,它虽然丑陋但有效。

package main

import (
    "fmt"
)

type I interface {
    foo(s string)   // Our "pure virtual" function
    bar()
}

type A struct {i I}
type B struct {A}
type C struct {B}

// fk receivers, this is a "member function" so I'll use OO nomenclature
func (this *A) init(i I) {
    this.i = i  // the i contains (internal) pointers to both an object and a type
}

func (this *A) bar() {
    this.i.foo("world")
}

func (this *B) foo(s string) {
    fmt.Printf("hello %s\n", s)
}

func (this *C) foo(s string) {
    fmt.Printf("goodbye cruel %s\n", s)
}

func main() {
    var i I
    b := &B{}
    b.init(b)   // passing b as the parameter implicitly casts it to an I interface object
    b.bar()
    c := &C{}
    c.init(c)
    c.bar()     // c is a pointer to C, so Golang calls the correct receiver

    i = b
    i.bar()
    i = c
    i.bar()     // Internally, i contains pointers to the C object and the C type,
            // so that the correct receiver is called
}

https://play.golang.org/p/4qBfmJgyuHC

在真正的 OO 语言中,具有任何虚函数的类的每个对象都必须有一个指向虚函数表或映射到它的最少类型的指针。因此,将接口成员添加到基(嵌入式)结构中只会浪费一个额外的机器字,用于指向其自身的指针。

或者,我们可以从 I 中删除 A 接口成员,并且具有纯虚成员函数只接受实现作为参数。

type I interface {
    foo(s string)
    bar(i I)
}

type A struct {}
type B struct {A}
type C struct {B}

func (this *A) bar(i I) {
    i.foo("world")
}

https://play.golang.org/p/9gvaCuqmHS8

但此时,foo 不再是纯虚函数,API 用户可以传递任何类型实现 I 的值,整个 OO 概念被打破。传递给 bar 的 I 接口的对象指针部分不需要与 this 相同,但是我们再次不需要使用 init() 传递相同的值函数,但至少只允许同一包中的 API 用户设置它。

此时,我们已经过渡到 Go 的做事方式:使用依赖注入的组合式编程。这就是 Ken Thompson 和其他设计师认为的更好的方法——至少对于他们既定的目标而言。虽然它在许多方面非常逊色,但它确实创造了许多优势,我不会在这里争论这些点。