定义
基本语法
type 接口名 interface {
method1(参数列表) 返回值列表
method2(参数列表) 返回值列表
}
例子:多态
type Animal interface {
Eat()
Drink()
}
type Dog struct {
}
func (X Dog) Eat(){
fmt.Println("狗爱吃骨头")
}
func (X Dog) Drink(){
fmt.Println("狗爱喝骨头汤" )
}
type Cat struct {
}
func (J Cat) Eat(){
fmt.Println("猫爱吃鱼")
}
func (J Cat) Drink(){
fmt.Println("猫爱喝鱼汤")
}
type Person struct {
}
func (P *Person) Feed(A Animal) {
A.Eat()
A.Drink()
}
func main() {
p :=Person{}
d :=Dog{}
c :=Cat{}
p.Feed(d)
p.Feed(c)
}
//------------------
如果Dog与Cat绑定方法时,用的是指针
func (X *Dog) Eat(){
fmt.Println("狗爱吃骨头")
}
那么在main方法中,在调用时
p.Feed(d)应改为p.Feed(&d),否则语法不通过
原因:一个变量实现了某个接口后,在接口内部不能获取到该变量的地址(不可寻址)
所以在p.Feed时,就需要传一个地址过去
注意事项
- 接口只定义方法名,不能有方法体
- 接口中不能有变量
- 接口的实现:一个变量实现了接口所有的方法(当然它还可以有自己的方法),那么称这个变量实现了该接口
- 只要是自定义数据类型都可以实现接口,不一定要是结构体
- 一个自定义类型可以实现多个接口
- 一个接口A,如果继承了其他的接口B,C。在实现A时,必须将B,C中的方法也实现。同时也需要注意,B,C中没有相同的方法,否则A接口的方法重复定义
- 任何类型都实现了空接口
sort.Sort(data Interface)
```goStudent中的Score进行升序排列
type Student struct { Name string Age int Score float64 }
type Students []Student
func (S Students) Len() int{ return len(S) } func (S Students) Less(i, j int) bool{ return S[i].Score<S[j].Score } func (S Students) Swap(i, j int){ S[i],S[j]=S[j],S[i] } func main() { S :=Student{} var SS Students rand.Seed(time.Now().UnixNano()) for i:=1;i<=5;i++{ S.Name=fmt.Sprintf(“小明%v号”,i) S.Age=rand.Intn(30) S.Score=float64(rand.Intn(100)) SS=append(SS,S) } fmt.Println(SS)//[{小明1号 20 44} {小明2号 13 39} {小明3号 3 79} {小明4号 28 18} {小明5号 8 27}] sort.Sort(SS) fmt.Println(SS)//[{小明4号 28 18} {小明5号 8 27} {小明2号 13 39} {小明1号 20 44} {小明3号 3 79}] }
<a name="Tpdl1"></a>
#
<a name="DSLpY"></a>
# 断言
<a name="EQ4Uw"></a>
### 用法
```go
func main() {
var a interface{}
b :=11.11
a=b//空接口类型的值可以接受任意类型的值
if c,flag:=a.(float64); flag{
fmt.Println(c)
}else {
fmt.Println("转型失败!!!")
}
}
断言实践:多态
type Animal interface {
Eat()
Drink()
}
type Dog struct {
}
func (X Dog) Eat(){
fmt.Println("狗爱吃骨头")
}
func (X Dog) Drink(){
fmt.Println("狗爱喝骨头汤" )
}
func (X Dog) Call(){
fmt.Println("狗:汪汪汪" )
}
type Cat struct {
}
func (J Cat) Eat(){
fmt.Println("猫爱吃鱼")
}
func (J Cat) Drink(){
fmt.Println("猫爱喝鱼汤")
}
type Person struct {
}
func (P *Person) Feed(A Animal) {
A.Eat()
A.Drink()
if b,flag :=A.(Dog);flag{
b.Call()
}//如果不检验,由于Cat中没有Call(),会编译不通过
}
func main() {
var arr =[...]Animal{
Dog{},
Cat{},
}
P :=Person{}
for _,v :=range arr{
P.Feed(v)
}
}
断言实践:类型判断
type Student2 struct {
}
func Judge(items ...interface{}){
for i,v :=range items{
i++
switch v.(type) {
case int,int8,int16,int32,int64:
fmt.Printf("第%v个参数的类型是--int\n",i)
case float64,float32:
fmt.Printf("第%v个参数的类型是--float\n",i)
case bool:
fmt.Printf("第%v个参数的类型是--bool\n",i)
case string:
fmt.Printf("第%v个参数的类型是--string\n",i)
case *Student2:
fmt.Printf("第%v个参数的类型是--*Student2\n",i)
case Student2:
fmt.Printf("第%v个参数的类型是--Student2\n",i)
default:
fmt.Printf("第%v个参数的类型不确定\n",i)
}
}
}
func main() {
a:=1
b:=1.0
c:=true
d:="旺财"
e:=&Student2{}
f:=Student2{}
g :=make([]int,10)
Judge(g,a,b,c,d,e,f)
}
空接口的陷阱
- 在使用空接口做为数据类型时,在使用时一定要还原
type Cat struct {
Name string
Age string
}
func main() {
slice :=make([]interface{},3)
slice[0]=1
slice[1]="哈哈"
slice[2]=Cat{"小花","10"}
fmt.Println(slice)
c :=slice[2]
//a :=slice[0]
//a++ 基本数据类型也需要断言
//fmt.Println(c.Name) 编译不通过
newc,flag:=c.(Cat)
if !flag{
panic("断言失败")
}
fmt.Println(newc.Name)//小花
}
判断有没实现接口
type Printer interface {
Print()
}
type Java struct {
}
func (j Java) SystemOut() {
fmt.Println("java")
}
type Golang struct {
}
func (g Golang) Print() {
fmt.Println("golang")
}
func main() {
var g Golang
//var j Java
run111(g)
}
func run111(i interface{}) {
if p, ok := i.(Printer); ok {
p.Print()
} else {
fmt.Println("未实现Printer接口")
}
}