接口(interface)
- 接口是一种类型,一种抽象的类型
定义接口
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
声明接口变量
var 变量 接口名称
实现接口条件和用途
- 1,定义共有的方法say()
// 定义狗和狗的say()方法
type Dog struct {}
func (d Dog) say(){
fmt.Println("汪汪汪")
}
// 定义猫和猫的say()方法
type Cat struct {}
func (c Cat) say(){
fmt.Println("喵喵喵")
}
// 定义人和人的say()方法
type Person struct {
name string
}
func(p Person) say(){
fmt.Println("啊啊啊")
}
- 2,只要上面这些对象有定义接口中的指定方法:比如都有say()方法,那么就生成了这个 自定义名称 为 sayer 的interface接口类型
// 定义接口类型,只管你实现什么方法
type sayer interface { // 定义一个类型,抽象的类型,只要实现了say()这个方法的类型,都可以成为是sayer
say()
}
- 3,那么另一个函数调用这个接口,传参就传入这个自定义 sayer 类型,执行只要时sayer类型的say方法就可以执行
// 打的函数,需要接收arg参数,并且是sayer类型(上面定义好了,只要实现say()方法 的类型都是sayer类型)
func da(arg sayer){
arg.say() //不管传进来的是什么都要打它,打他就会叫,就要执行它的say的方法
}
- 4,执行定义的接口,执行公共的方法
func main() {
var c1 = Cat{}
da(c1)
var d1 = Dog{}
da(d1)
var p1 = Person{
name:"alex",
}
da(p1)
}
- 5,接口用途:当实现某个接口(sayer)之后,凡是有这个接口指定的方法(say())的对象,都可以保存在 s 接口类型的变量中
func main() {
var s sayer
var c2 = Cat{} //因为 Cat 有接口指定的方法(say())的对象
s = c2 //所以可以存在 sayer接口类型的变量 s 中
var p2 = Person{name: "alex"} //同理
s = p2
fmt.Println(s)
}
整体代码
package main
import "fmt"
// 定义狗和狗的方法
type Dog struct {}
func (d Dog)say(){
fmt.Println("汪汪汪")
}
// 定义猫和猫的方法
type Cat struct {}
func (c Cat)say(){
fmt.Println("喵喵喵")
}
// 定义人和人的方法
type Person struct {
name string
}
func(p Person)say(){
fmt.Println("啊啊啊")
}
// 定义接口类型,只管你实现什么方法
type sayer interface { // 定义一个类型,抽象的类型,只要实现了say()这个方法的类型,都可以成为是sayer
say()
}
// 打的函数,需要接收arg参数,并且是sayer类型(上面定义好了,只要实现say()方法 的类型都是sayer类型)
func da(arg sayer){
arg.say() //不管传进来的是什么都要打它,打他就会叫,就要执行它的say的方法
}
func main() {
//var c1 = Cat{}
//da(c1)
//
//var d1 = Dog{}
//da(d1)
//
//var p1 = Person{
// name:"alex",
//}
//da(p1)
var s sayer
var c2 = Cat{}
s = c2
var p2 = Person{name: "alex"}
s = p2
fmt.Println(s)
}
值接收 和 指针接收 实现接口的区别
值接收
- 使用 值接收 的接口:类型的值和类型的指针都能保存在接口变量中
package main
import "fmt"
//定义接口类型Mover
type Mover interface {
Move()
}
type Person struct {
name string
age int8
}
//使用 值接收 的接口:类型的值和类型的指针都能保存在接口变量中
func (p Person)Move(){
fmt.Printf("%s在跑\n",p.name)
}
func main() {
var m Mover //接口类型变量
var p1 = Person{ //Person是值类型
name: "alex",
age: 18,
}
var p2 = &Person{ //p2是Person类型的指针
name: "佩奇",
age: 19,
}
m = p1
m = p2
m.Move()
fmt.Println(m)
}
指针接收
package main
import "fmt"
//定义接口类型Mover
type Mover interface {
Move()
}
type Person struct {
name string
age int8
}
////使用 值接收 的接口:类型的值和类型的指针都能保存在接口变量中
//func (p Person)Move(){
// fmt.Printf("%s在跑\n",p.name)
//}
//如果Move方法是指针类型,只有实例化指针类型后,才能赋值给接口类型的变量中
//如果Move方法是值类型,只有实例化值类型后,才能赋值给接口类型的变量中
func (p *Person)Move(){
fmt.Printf("%s在跑\n",p.name)
}
func main() {
var m Mover //接口类型变量
//var p1 = Person{ //如果Move方法是值类型,只有实例化值类型后,才能赋值给接口类型的变量中
// name: "alex",
// age: 18,
//}
var p2 = &Person{ //p2是Person类型的指针,只有 类型的指针 才能够保存到接口变量中
name: "佩奇",
age: 19,
}
// m = p1 // 如果Move方法是指针类型,只有实例化指针类型后,才能赋值给接口类型的变量中
m = p2
m.Move()
fmt.Println(m)
}
区别
-
当前定义了接口类型Mover,和指定了 Move() 方法
-
//定义接口类型Mover type Mover interface { Move() }
-
-
当前定义了结构体
-
type Person struct { name string age int8 }
-
-
如果结构体的 Move() 方法是指针类型
*Person,只有实例化指针类型后,才能赋值给接口类型的变量中-
func (p *Person)Move(){ fmt.Printf("%s在跑\n",p.name) } -
func main() { var m Mover //接口类型变量 var p2 = &Person{ //p2是Person类型的指针,只有 类型的指针 才能够保存到接口变量中 name: "佩奇", age: 19, } m = p2 m.Move() fmt.Println(m) }
-
-
如果结构体的 Move() 方法是值类型
Person,只有实例化值类型后,才能赋值给接口类型的变量中-
//使用 值接收 的接口:类型的值和类型的指针都能保存在接口变量中 func (p Person)Move(){ fmt.Printf("%s在跑\n",p.name) } -
func main() { var m Mover //接口类型变量 var p1 = Person{ //如果Move方法是值类型,只有实例化值类型后,才能赋值给接口类型的变量中 name: "alex", age: 18, } m = p1 // 如果Move方法是指针类型,只有实例化指针类型后,才能赋值给接口类型的变量中 m.Move() fmt.Println(m) }
-
类型 和 接口 的区别
package main
import "fmt"
//定义接口类型Mover
type Mover interface {
Move()
}
type Sayer interface {
Say()
}
type Person struct {
name string
age int8
}
func (p *Person)Move(){
fmt.Printf("%s在跑\n",p.name)
}
func (p *Person)Say(){
fmt.Printf("%s在叫~\n",p.name)
}
func main() {
var p2 = &Person{ //p2是Person类型的指针,只有 类型的指针 才能够保存到接口变量中
name: "佩奇",
age: 19,
}
var m Mover //定义Mover接口类型的变量
m = p2
m.Move()
fmt.Println(m) //佩奇在跑
var s Sayer //定义Sayer类型的变量
s = p2
s.Say()
fmt.Println(s) //佩奇在叫
}
接口嵌套
package main
import "fmt"
//接口的嵌套
type Animal interface {
Mover
Sayer
}
//定义接口类型Mover
type Mover interface {
Move()
}
type Sayer interface {
Say()
}
type Person struct {
name string
age int8
}
func (p *Person)Move(){
fmt.Printf("%s在跑\n",p.name)
}
func (p *Person)Say(){
fmt.Printf("%s在叫~\n",p.name)
}
func main() {
var m Mover //定义Mover接口类型的变量
var p2 = &Person{
name: "佩奇",
age: 19,
}
m = p2
m.Move() //佩奇在跑
fmt.Println(m)
var s Sayer //定义Sayer类型的变量
s = p2
s.Say() //佩奇在叫
fmt.Println(s)
var a Animal //定义Animal类型的变量
a = p2
a.Move()
a.Say()
fmt.Println(a)
}
空接口 interface{}
-
空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。
-
空接口类型的变量可以存储任意类型的变量。
空接口 interface{} 的应用
1,作为函数的参数,可以传任何类型
fmt.Println()
Println() 函数中参数就是 interface{} 空接口类型,所以可以打印任何类型
2,可以作为map的value值
func main() {
var m = make(map[string]interface{},16) //定义初始化map的key是string,value 为空接口什么都可以传
m["name"] = "alex" //string类型
m["age"] = 18 //int类型
m["aihao"] = []string{"唱","跳","rap","篮球"} //切片类型
fmt.Println(m)
}
类型断言

想要判断空接口中的值这个时候就可以使用类型断言,其语法格式:
x.(T)
其中:
- x:表示类型为
interface{}的变量 - T:表示断言
x可能是的类型。
该语法返回两个参数,第一个参数是x转化为T类型后的变量,第二个值是一个布尔值,若为true则表示断言成功,为false则表示断言失败。
func main() {
var x interface{}
x = false
var ret,ok = x.(string) //类型断言,猜对了ok是true,如果猜错了ok是false,并且ret是对应类型的零值
fmt.Println(ret)
fmt.Println(ok)
if ok == true {
fmt.Println("猜对了,是",ret)
}else {
fmt.Println("猜错了,是",ret)
}
}
或者另一种switch写法进行类型断言
func main() {
var x interface{}
x = false
switch v := x.(type) {
case string:
fmt.Printf("是string类型,value:%v\n", v)
case bool:
fmt.Printf("是bool类型,value:%v\n", v)
case int:
fmt.Printf("是int类型,value:%v\n", v)
default:
fmt.Printf("猜不到了,value:%v\n", v)
}
}
浙公网安备 33010602011771号