go 学习笔记:interface接口

Posted on 2021-02-18 00:33  王石头py  阅读(75)  评论(0)    收藏  举报

接口(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)
	}
}