1.接口的定义
在Go语言中,接口(interface)是一个自定义类型,接口类型具体描述了一系列方法的集合。
接口类型是一种抽象的类型,他不会暴漏出他所代表的对象的内部值的结构和这个对象支持的基础操作的集合,他们只会展示出他们自己的方法。因此接口类型不能将其实例化。
Go语言通过接口实现了鸭子类型(duck-typing):“当看到一直鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
接口定义
Type Humaner interface{
SayHi()
}
- 接口命名习惯以er结尾
- 接口只有方法声明,没有实现,没有数据字段
- 接口可以匿名嵌入其他接口,或嵌入到结构中
例子:
package main import "fmt" //定义接口类型 type Humaner interface { SayHi() //方法只有声明没有实现,有别的类型(自定义类型)实现 } type Student struct { name string id int } //Student实现此方法 func (tmp *Student) SayHi() { fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id) } type Teacher struct { addr string group string } //Teacher实现此方法 func (tmp *Teacher) SayHi() { fmt.Printf("Teacher[%s, %s] sayhi\n", tmp.addr, tmp.group) } type Mystr string //Mystr实现此方法 func (tmp *Mystr) SayHi() { fmt.Printf("Mystr[%s] sayhi\n", *tmp) } func main() { //定义接口类型变量 var i Humaner //只要实现了此接口方法的类型,那么这个类型的变量(接收者类型)就可以给i赋值 s := &Student{"mike", 18} i = s i.SayHi() t := &Teacher{"bj", "go"} i = t i.SayHi() var str Mystr = "Hello world" i = &str i.SayHi() }
输出:
2.多态的表现
package main
import "fmt"
//定义接口类型
type Humaner interface {
SayHi() //方法只有声明没有实现,有别的类型(自定义类型)实现
}
type Student struct {
name string
id int
}
//Student实现此方法
func (tmp *Student) SayHi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
type Teacher struct {
addr string
group string
}
//Teacher实现此方法
func (tmp *Teacher) SayHi() {
fmt.Printf("Teacher[%s, %s] sayhi\n", tmp.addr, tmp.group)
}
type Mystr string
//Mystr实现此方法
func (tmp *Mystr) SayHi() {
fmt.Printf("Mystr[%s] sayhi\n", *tmp)
}
func WhoSayHi(i Humaner) {
i.SayHi()
}
func main() {
s := &Student{"mike", 18}
t := &Teacher{"bj", "go"}
var str Mystr = "Hello mike"
//调用同一函数,不同表现,多态,多种形态
WhoSayHi(s)
WhoSayHi(t)
WhoSayHi(&str)
//方法二创建一个切片
x := make([]Humaner, 3)
x[0] = s
x[1] = t
x[2] = &str
//第一个返回下标,第二个返回下标所对应的值
for _, i := range x {
i.SayHi()
}
}
输出:
3.接口的继承
package main
import "fmt"
//定义接口类型
type Humaner interface {
SayHi() //方法只有声明没有实现,有别的类型(自定义类型)实现
}
type Personer interface {
Humaner //匿名字段,继承了SayHi()
sing(lrc string)
}
type Student struct {
name string
id int
}
func (tmp *Student) SayHi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
func (tmp *Student) sing(lrc string) {
fmt.Printf("Student在唱:%s\n", lrc)
}
func main() {
//定义一个接口类型变量
var i Personer
s := &Student{"mike", 666}
i = s
i.SayHi() //继承过来的方法
i.sing("学生歌")
}
输出:
4.接口转化
package main
import "fmt"
//定义接口类型
type Humaner interface { //子集
SayHi() //方法只有声明没有实现,有别的类型(自定义类型)实现
}
type Personer interface { //超集
Humaner //匿名字段,继承了SayHi()
sing(lrc string)
}
type Student struct {
name string
id int
}
func (tmp *Student) SayHi() {
fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}
func (tmp *Student) sing(lrc string) {
fmt.Printf("Student在唱:%s\n", lrc)
}
func main() {
//超集可以转化为子集,反过来不可以。
var iPro Personer //超集
iPro = &Student{"mike", 666}
var i Humaner //子集
i = iPro //可以,超集可以转化为子集
i.SayHi()
}
输出:
5.空接口
空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任何类型的数值,当函数可以接受任意的对象实例时,我们会将其声明为interface{}。
package main import "fmt" func main() { //空接口是万能类型,保存任意类型的值 var i interface{} = 1 fmt.Println("i = ", i) i = "abc" fmt.Println("i = ", i) }
输出:
6.通过if实现类型断言
package main
import "fmt"
type Student struct {
name string
id int
}
func main() {
i := make([]interface{}, 3)
i[0] = 1 //int
i[1] = "Hello go" //string
i[2] = Student{"mike", 666} //Student
//类型查询,类型断言
//第一个返回下标,第二个返回下标对应的值,data分别是i[0],i[1],i[2]
for index, data := range i {
//第一个返回的是值,第二返回判断结果真假
if value, ok := data.(int); ok == true {
fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value)
} else if value, ok := data.(string); ok == true {
fmt.Printf("x[%d] 类型为string,内容为%s\n", index, value)
} else if value, ok := data.(Student); ok == true {
fmt.Printf("x[%d] 类型为Student,内容为%v\n", index, value)
}
}
}
输出:
7.通过switch实现类型断言
package main
import "fmt"
type Student struct {
name string
id int
}
func main() {
i := make([]interface{}, 3)
i[0] = 1 //int
i[1] = "Hello go" //string
i[2] = Student{"mike", 666} //Student
//类型查询,类型断言
//第一个返回下标,第二个返回下标对应的值,data分别是i[0],i[1],i[2]
for index, value := range i {
switch value.(type) {
case int:
fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value)
case string:
fmt.Printf("x[%d] 类型为string,内容为%s\n", index, value)
case Student:
fmt.Printf("x[%d] 类型为Student,内容为%v\n", index, value)
default:
fmt.Println("error")
}
}
}
输出: