摘要
Go语言中的接口和Java中的接口在定义方面区别不是特别大,当然也有区别,比如Go接口中不能有数据字段,可以嵌套接口;但是却在实现是大有不同,Java中一种类型(类)要实现某个接口则需要通过implements关键指名实现的接口名称,而Go中任何类型的方法集中只要拥有与接口对应的全部方法,就表明它 "实现" 了该接口,不用在该类型上显式添加接⼝声明。
接口定义
type Ier interface {
hello() string
}
type Nuller interface {
}
上面定义了两个接口,接口Ier声明了一个方法,接口Nuller没有声明方法,通常没有声明方法的接口称为空接口
或者标记接口
,这就意味着任何类型都实现了空接口,作用和Java中的Object相似。
实现接口
type Chinese struct {
}
func (this *Chinese) hello() string {
return "你好"
}
type Japanese struct {
}
func (this *Japanese) hello() string {
return "こんにちは"
}
type English struct {
}
func (this *English) hello() string {
return "Hello"
}
func (this *English) f1(){
}
func (this *English) f2(){
}
上面定义了三种类型,分别都定义和Ier接口方法签名相同的方法,因此这种类型都实现了Ier接口,同时也都实现了Nuller接口
定义函数
func greeting(ier Ier) {
fmt.Println(ier.hello())
}
在定义函数的时候参数类型为接口类型,运行时将根据传递给函数的目标对象来运行对应实现的方法。
- 如果目标对象的类型结构体中方法的
recevier
(接收者)是指针类型,则greeting函数传入的是一个指针对象。如果传入值对象将运行时错误,如下所示:
func (this *Chinese) hello() string {
return "你好"
}
//直接传入值对象
greeting(Chinese{})
//输出
.\appath.go:54: cannot use Chinese literal (type Chinese) as type Ier in argument to greeting:
Chinese does not implement Ier (hello method has pointer receiver)
- 如果目标对象的类型结构体中方法的
recevier
(接受者)是值类型,则greeting函数传入的参数可以是值对象,也可以是指针对象。
func (this Chinese) hello() string {
return "你好"
}
-
产生上诉问题的原因是:每中类型都有与之关联的方法集参考:Go学习笔记第四版5.3方法集
- 类型
T
的方法集包含全部receiver T
的方法 - 类型
*T
的方法集包含全部receiver T + *T
的方法 - 类型
S
包含匿名字段T
, 则S
的方法集包含T
的方法 - 类型
S
包含匿名字段*T
, 则S
的方法集包含T + *T
的方法 - 不管嵌入
T
或*T
, 则*S
的方法集总是包含T + *T
的方法
- 类型
测试
- 代码示例
chinese := &Chinese{}
japanese := &Japanese{}
english := &English{}
var iers = [...]Ier{
chinese, japanese, english,
}
//不同语言的问候
for _, ier := range iers {
greeting(ier)
}
- 输出结果
你好
こんにちは
Hello
类型判断
- 代码示例
//类型判断
fmt.Println("类型判断")
var typeassert = func(ier interface{}) {
if v, ok := ier.(Chinese); ok {
fmt.Printf("%T is Chinese Type \n", v)
}
if v, ok := ier.(*Chinese); ok {
fmt.Printf("%T is Pointer to Chinese Type \n", v)
}
if v, ok := ier.(Japanese); ok {
fmt.Printf("%T is Japanese Type \n", v)
}
if v, ok := ier.(*Japanese); ok {
fmt.Printf("%T is Pointer to Japanese Type \n", v)
}
if v, ok := ier.(English); ok {
fmt.Printf("%T is English Type \n", v)
}
if v, ok := ier.(*English); ok {
fmt.Printf("%T is Pointer to English Type \n", v)
}
}
ier = new(English)
typeassert(ier)
ier = Chinese{}
typeassert(ier)
- 输出结果
类型判断
*main.English is Pointer to English Type
main.Chinese is Chinese Type
类型转换
- 代码示例
var ier interface{}
// 类型转换
fmt.Println("类型转换")
var typeswitch = func(ier interface{}) {
switch t := ier.(type) {
case Chinese:
fmt.Printf("Chinese Type %T\n", t)
case *Chinese:
fmt.Printf("Pointer to Chinese Type %T\n", t)
case Japanese:
fmt.Printf("Japanese Type %T\n", t)
case *Japanese:
fmt.Printf("Pointer to Japanese Type %T\n", t)
case English:
fmt.Printf("English Type %T\n", t)
case *English:
fmt.Printf("Pointer to English Type %T\n", t)
default:
fmt.Printf("unexpected type %T\n", t)
}
}
ier = Chinese{}
typeswitch(ier)
ier = &English{}
typeswitch(ier)
- 输出结果
类型转换
Chinese Type main.Chinese
Pointer to English Type *main.English