接口interface

接口interface
定义:接口是一种抽象的类型,是一组method的集合,里头只有method方法,没有数据成员。当两个或两个以上的类型都有相同的处理方法时才需要用到接口。先定义接口,然后多个struct类型去实现接口里的方法,就可以通过接口变量去调用struct类型里实现的方法。

比如动物都会叫唤,那可以先定义一个名为动物的接口,接口里有叫唤方法speak,然后猫和狗这2个struct类型去实现各自的speak方法。

语法:

// 定义接口
type interface_name interface {
method_name1([参数列表]) [返回值列表]
method_name2([参数列表]) [返回值列表]
method_nameN([参数列表]) [返回值列表]
}

// 定义结构体类型
type struct_name struct {
data_member1 data_type
data_member2 data_type
data_memberN data_type
}

// 实现接口interface_name里的方法method_name1
func(struct_var struct_name) method_name1([参数列表])[返回值列表] {
/具体方法实现/
}

// 实现接口interface_name里的方法method_name2
func(struct_var struct_name) method_name2([参数列表])[返回值列表] {
/具体方法实现/
}

/* 实现接口interface_name里的方法method_name3
注意:下面用了指针接受者。函数可以使用值接受者或者指针接受者,上面的method_name1和method_name1使用的是值接受者。
如果用了指针接受者,那给interface变量赋值的时候要传指针
*/
func(struct_var *struct_name) method_name3([参数列表])[返回值列表] {
/具体方法实现/
}

示例:

package main

import “fmt”

// all animals can speak
type Animal interface {
speak()
}

// cat
type Cat struct {
name string
age int
}

func(cat Cat) speak() {
fmt.Println(“cat miaomiaomiao”)
}

// dog
type Dog struct {
name string
age int
}

func(dog *Dog) speak() {
fmt.Println(“dog wangwangwang”)
}

func main() {
var animal Animal = Cat{“gaffe”, 1}
animal.speak() // cat miaomiaomiao

/*
因为Dog的speak方法用的是指针接受者,因此给interface赋值的时候,要赋指针
*/
animal = &Dog{"caiquan", 2}
animal.speak() // dog wangwangwang

}
struct结构体类型在实现interface里的所有方法时,关于interface变量赋值有2个点要注意

只要有某个方法的实现使用了指针接受者,那给包含了这个方法的interface变量赋值的时候要使用指针。比如上面的Dog类型要赋值给Animal,必须使用指针,因为Dog实现speak方法用了指针接受者。

如果全部方法都使用的是值接受者,那给interface变量赋值的时候用值或者指针都可以。比如上面的例子,animal的初始化用下面的方式一样可以:

var animal Animal = &Cat{“gaffe”, 1}
多个struct类型可以实现同一个interface:多个类型都有共同的方法(行为)。比如上面示例里的猫和狗都会叫唤,猫和狗就是2个类型,叫唤就是speak方法。

一个struct类型可以实现多个interface。比如猫这个类型,既是猫科动物,也是哺乳动物。猫科动物可以是一个interface,哺乳动物可以是另一个interface,猫这个struct类型可以实现猫科动物和哺乳动物这2个interface里的方法。

package main

import “fmt”

// interface1,猫科动物的共同行为
type Felines interface {
feet()
}

// interface2, 哺乳动物的共同行为
type Mammal interface {
born()
}

// 猫既是猫科动物也是哺乳动物,2个行为都实现
type Cat struct {
name string
age int
}

func(cat Cat) feet() {
fmt.Println(“cat feet”)
}

func(cat *Cat) born() {
fmt.Println(“cat born”)
}

func main() {
cat := Cat{“rich”, 1}
var a Felines = cat
a.feet()

var b Mammal = &cat
b.born()

}
interface可以嵌套:一个interface里包含其它interface

package main

import “fmt”

// interface1
type Felines interface {
feet()
}

// interface2, 嵌套了interface1
type Mammal interface {
Felines
born()
}

// 猫实现Mammal这个interface里的所有方法
type Cat struct {
name string
age int
}

func(cat Cat) feet() {
fmt.Println(“cat feet”)
}

func(cat *Cat) born() {
fmt.Println(“cat born”)
}

func main() {
cat := Cat{“rich”, 1}
/Mammal有feet和born方法,2个都可以调用/
var a Mammal = &cat
a.feet()
a.born()

var b Felines = cat
b.feet()
// b.born() 调用这个会编译报错,因为Felines没有born方法

}
空接口interface

如果空interface作为函数参数,可以接受任何类型的实参

语法

func function_name(x interface{}) {
do sth
}

  • 示例

    package main
    
    import "fmt"
    
    
    type Cat struct {
        name string
        age int
    }
    
    // 打印空interface的类型和具体的值
    func print(x interface{}) {
        fmt.Printf("type:%T, value:%v\n", x, x)
    }
    
    func main() {
        // 传map实参给空接口
        dict := map[string]int{"a":1}
        print(dict) // type:map[string]int, value:map[a:1]
        
        // 传struct实参给空接口
        cat := Cat{"nimo", 2}
        print(cat) // type:main.Cat, value:{nimo 2}
    }
    

如果空interface作为变量,可以把任何类型的变量赋值给空interface

语法

var x interface{} // 空接口x
示例

package main

import “fmt”

type Cat struct {
name string
age int
}

// 打印空interface的类型和具体的值
func print(x interface{}) {
fmt.Printf(“type:%T, value:%v\n”, x, x)
}

func main() {
// 定义空接口x
var x interface{}
// 将map变量赋值给空接口x
x = map[string]int{“a”:1}
print(x) // type:map[string]int, value:map[a:1]

// 传struct变量估值给空接口x
cat := Cat{"nimo", 2}
x = cat
print(x) // type:main.Cat, value:{nimo 2}

}
空接口作为map的值,可以实现map的value是不同的数据类型

语法

// 定义一个map类型的变量,key是string类型,value是空接口类型
dict := make(map[string]interface{})

  • 示例

    package main
    
    import "fmt"
    
    
    func main() {
        // 定义一个map类型的变量,key是string类型,value是空接口类型
        dict := make(map[string]interface{})
        // value可以是int类型
        dict["a"] = 1 
        // value可以是字符串类型
        dict["b"] = "b"
        // value可以是bool类型
        dict["c"] = true
        fmt.Println(dict) // map[a:1 b:b c:true]
        fmt.Printf("type:%T, value:%v\n", dict["b"], dict["b"]) // type:string, value:b
    }
    

x.(T)

断言:断言接口变量x是T类型

语法:value是将x转化为T类型后的变量,ok是布尔值,true表示断言成功,false表示断言失败

// x是接口变量,如果要判断x是不是
value, ok := x.(string)
示例

var x interface{}
x = “a”
// 断言接口变量x的类型是string
v, ok := x.(string)
if ok {
// 断言成功
fmt.Println(“assert true, value:”, v)
} else{
// 断言失败
fmt.Println(“assert false”)
}
动态判断数据类型

package main

import “fmt”

func checkType(x interface{}) {
/动态判断x的数据类型/
switch v := x.(type) {
case int:
fmt.Printf(“type: int, value: %v\n”, v)
case string:
fmt.Printf(“type: string,value: %v\n”, v)
case bool:
fmt.Printf(“type: bool, value: %v\n”, v)
case Cat:
fmt.Printf(“type: Cat, value: %v\n”, v)
case map[string]int:
fmt.Printf(“type: map[string]int, value: %v\n”, v)
v[“a”] = 10
default:
fmt.Printf(“type: %T, value: %v\n”, x, x)
}
}

type Cat struct {
name string
age int
}

func main() {
var x interface{}
x = “a”
checkType(x) //type: string,value: a

x = Cat{"hugo", 3}
checkType(x) // type: Cat, value: {hugo 3}

/*在checkType里对map做修改
会影响外面的实参x
*/
x = map[string]int{"a":1}
checkType(x) // type: map[string]int, value: map[a:1]
fmt.Println(x) // map[a:10]

}
注意事项

如果把一个结构体变量赋值给interface变量,那结构体需要实现interface里的所有方法,否则会编译报错:xx does not implement yy,表示结构体xx没有实现接口yy

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值