开发工具:Goland
示例代码
package main
import "fmt"
type Computer interface {
Calculator
Play(string) string
}
type Calculator interface {
Open(string) Calculator
Say() string
Add(uint, uint)
Sum(int, int) int
}
type TOM struct {
Name string
Age int
Bob *BOB
}
type BOB struct {
TOM
MyName string
}
func (t *TOM) Open(s string) Calculator {
return t
}
func (t *TOM) Say() string {
return "I am " + t.Name
}
func (t *TOM) Add(a, b uint) {
fmt.Println(a + b)
}
func (t *TOM) Sum(a, b int) int {
return a + b
}
func (t *TOM) Play(s string) string {
return s
}
func (b *BOB) Say() string {
return "My Name is " + b.MyName
}
func main() {
b := new(BOB)
b.MyName = "Bob"
t := new(TOM)
t.Name = "Tom"
t.Age = 12
fmt.Println(t.Say())
}
一个struct
(结构体)如何实现一个interface
(接口)
在Go语言中,一个struct实现了某个接口里的所有方法,叫做这个struct实现了该接口。
比如上面的例子中,接口Calculator
中共有四个方法
Open(string) Calculator
Say() string
Add(uint, uint)
Sum(int, int) int
而结构体TOM
必须要实现这全部4个方法,才叫做结构体BOB
实现了Calculator
接口,
在Goland编译器中,如果一个结构体实现了某个接口,这个结构体的源码旁边就会显示接口实现标记,
一个绿底色的?,旁边一个向上的红色箭头↑,点击这个标记,就能看到该结构体实现了哪些类,
如果TOM只实现了三个方法,那TOM就没有实现Calculator
接口,而Goland工具上也不会显示这个标记
而如果一个接口里的【所有方法
】,都被某个struct实现了,那么这个接口的源码旁边也同样会被标记,有struct实现了这个接口,
一个绿底色的?,和一个向下的黑箭头↓,点击这个标志,就能看到哪些struct实现了这个interface,
然后点击struct,就能查看这些struct的源码定义。
struct(结构体)嵌套
当一个结构体A将另一个结构体B作为其中一个字段时(仅将结构体作为字段;而不是声明一个变量,其类型为结构体B),结构体A就可以直接调用结构体B所绑定的方法,同时也拥有了结构体B中的字段(变量);如果结构体B实现了某个接口E
,那么,此时,结构体A也自动实现了接口E
,
比如上面例子中,结构体TOM
是结构体BOB
中的一个字段,所以结构体BOB
并没有全部绑定接口Calculator
中的四个方法,但是可以看到结构体BOB
也实现了接口Calculator
,
不过这里要注意的是,BOB
将TOM
本身作为一个字段,
而不是定义一个变量,该变量的类型是TOM
,
将TOM
作为变量t
的类型,这种情况,结构体BOB
就不能直接调用TOM
所绑定的方法,结构体BOB
也就没有实现接口Calculator
,
结构体BOB
只能调用变量t
,然后用变量t
来调用TOM
所绑定的方法。
方法重写
示例代码
package main
import "fmt"
type TOM struct {
Name string
Age int
Bob *BOB
n int
}
type BOB struct {
TOM
MyName string
}
func (t *TOM) Open(s string) {
}
func (t *TOM) Say(string) string {
return "I am " + t.Name
}
func (t *TOM) Add(a, b uint) {
fmt.Println(a + b)
}
func (t *TOM) Sum(a, b int) int {
return a + b
}
func (t *TOM) Play(s string) string {
return s
}
func (b *BOB) Say(string) string {
return "My Name is " + b.MyName
}
func main() {
b := new(BOB)
b.MyName = "Bob"
fmt.Println(b.n)
t := new(TOM)
t.Name = "Tom"
t.Age = 12
fmt.Println(t.Say(""))
}
这个例子中结构体BOB
把TOM
本身作为字段的时候,BOB
就可以直接调用TOM
中所有的变量(包括小写字母开头的私有变量),和所有的方法,我们把这种情况叫做【继承】(暂且叫做继承吧)。
结构体BOB
继承了TOM
,此时结构体BOB
已经可以直接调用TOM
绑定的所有方法了,但是BOB
自己又绑定了一个与TOM
的某个方法的方法名相同、参数相同,返回值类型也相同的一个方法Say()
,这种情况,叫做【方法重写】。
意思就是结构体BOB
重写了结构体TOM
绑定的方法Say()
,内部做了与之前TOM
所绑定的Say()
方法不同的处理。
在Goland编译器中,当一个struct的某个方法被重写的时候,这个方法的旁边会有一个方法重写的提示,
一个蓝底色的圆圈,和一个向下的黑色箭头,
这个标志,表示该方法被重写,点击这个标志,就可以查看哪个struct重写了该方法,
再点击这个弹出来的struct,就可以看到被重写后的方法,
相应的,如果一个方法重写了某个方法,Goland也会有提示,
一个蓝底色的圆圈,和一个向上的红色箭头↑,
代表该方法重写了另一个方法,点击这个标志,就可以直接跳到原来的方法上
当一个结构体A重写了结构体B的方法,在调用时,结构体A会调用自己所绑定的方法,也就是被A重写后的方法,而结构体B只能调用自己原来的方法,也就是重写前的方法;
不过A也可以调用重写前的方法,但是要通过B来调用,也就是A调用字段B,再调用原来的方法。
可以看到这里的Say()方法是被结构体BOB
绑定的,
而在调了TOM
后,也可以调用Say()方法,不过此时调用的Say()是被TOM
绑定的。
最后再说说Go语言里面的实现方法,一个结构体要实现一个接口,就要实现这个接口里的所有方法,这里的实现是指,给该结构体绑定与接口里的方法声明完全相同的方法,即方法名相同(包括大小写相同),参数类型和参数个数相同,返回值个数和类型也相同。