在go语言中,接口就是一种类型。同map、struct等的定义,语法是一样的。
如:
type People interface {
Speak(string) string
}
关键字是interface。此时就称People是一个接口。接口内只有方法声明,没有方法的实现,也没有数据字段。
接口的作用就是定义一些对象的共同特征,特征以接口内的方法来定义。如上例的speak方法。
具有上述特征的类型,那就称它实现了这个接口。语法如下:
// 定义类型Student,它是一种struct类型
type Student struct{}
// 类型Student实现People特征 (也就是让它实现People中的方法)
func (stu Student) Speak(think string) (talk string) {
if think == "hello world" {
talk = "你好,世界"
} else {
talk = "您好"
}
return
}
实现好之后,Student对象就可以赋值给People类型变量了
var peo People = Student{}
think := "hello"
fmt.Println(peo.Speak(think))
上面代码输出:您好。
除了值类型能实现接口,指针类型也能实现接口,所谓指针类型实现是指如上面的speak实现,接收者改成指针声明。如下:
type Doctor struct{}
func (stu *Doctor) Speak(think string) (talk string) {
if think == "check" {
talk = "检查"
} else {
talk = "治疗"
}
return
}
同一种类型不能有两个同名的方法实现,指针和值接收者也算同一种类型,如上面有student值接收者实现了speak,不能再有student指针接收者实现speak。
值接收者实现和指针接收者实现的区别:
func main() {
var peo People = Student{}
think := "hello"
fmt.Println(peo.Speak(think))
var peo2 People = &Student{}
fmt.Println(peo2.Speak("hello world"))
//var peo3 People = Doctor{}
//fmt.Println(peo3.Speak("money"))
var peo4 People = &Doctor{}
fmt.Println(peo4.Speak("check"))
}
注意,Doctor{}不能赋值给People类型的变量,会报错:cannot use Doctor{} (type Doctor) as type People in assignment:Doctor does not implement People (Speak method has pointer receiver)。意思就是Doctor对象并没有实现People接口。也就是说:值接收者实现接口时,对象和其指针都能赋值给相应的接口类型,而指针接收者实现的对象只能把其指针赋值给相应的接口类型。
一个类型可以实现多个接口,比如学生还能实现孩子接口,拥有学习的特征
type Children interface {
Study(string) string
}
func (stu Student) Study(book string) (obtain string) {
if book == "math" {
obtain = "计算"
} else {
obtain = "其他"
}
return
}
func main(){
var peo2 People = &Student{}
fmt.Println(peo2.Speak("hello world"))
var peo5 Children = Student{}
fmt.Println(peo5.Study("math"))
}
接口嵌套
定义一个接口的时候可以嵌套别的接口,这样就会拥有该接口的特征。
type Boy interface {
People
Children
}
func main(){
var xiaoming Boy = Student{}
fmt.Println(xiaoming.Speak("hello world"))
fmt.Println(xiaoming.Study("english"))
}
如上面例子中的Boy。它嵌套了两个接口,拥有了这两个接口的特征Speak和Study。而Student类型有实现这两个特征,也就相当于实现了Boy接口,所以Student对象可以赋值给Boy类型的变量。
空接口
空接口就是没有特征的接口类型,也就是没有定义任何方法。
type Empty interface {}
所以说在Go中,任何类型都实现了空接口。也就是指任何类型的变量都可以赋值给空接口类型的变量。那应该如何判断当前空接口所接收的类型呢。可以用x.(T)方法或者x.(type)。x为空接口类型变量。用法如下:
func justifyType(x interface{}) {
switch v := x.(type) {
case string:
fmt.Printf("x is a string,value is %v\n", v)
case int:
fmt.Printf("x is a int is %v\n", v)
case bool:
fmt.Printf("x is a bool is %v\n", v)
default:
fmt.Println("unsupport type!")
}
v, ok := x.(string)
if ok {
fmt.Printf("I am string. value is %v type is %T\n", v, v)
} else {
fmt.Printf("I am not string. value is %v type is %T\n",v, v)
}
}
func main(){
var a int = 88
var b string = "hello"
justifyType(a)
justifyType(b)
}
x.(T): T是某种类型,比如x.(string),它会返回两个值,后一个值表示当前类型是不是string的布尔值,如果为true,则前一个值表示解析出来的值,类型也相应转为string,否则为空。
x.(type): 返回当前的类型,比如string。只能在switch中使用,否则编译不过。
上面例子会输出:
x is a int is 88
I am not string. value is type is string
x is a string,value is hello
I am string. value is hello type is string