golang接口 | 青训营

118 阅读5分钟

1.介绍

  • 假如你想要记录自己的想法,那么笔和纸并不是你的唯一工具,手边的铅笔和餐纸也可以实现同样的目的。无论你想要在笔记本上写备忘录,在工作用纸写标语等,蜡笔,记号笔和自动铅笔都可以满足你的需求,书写是非常灵活的。

  • 装有黑色墨水的0.5mm的圆珠笔是一件具体的物体,但书写工具却是一个模糊的概念,而接口就是代码用来表达抽象概念的。

2.接口的使用:

  • 大多数类型关心的是自己存储的值,而接口类型关注的是做了什么。
    类型通过方法表示自己的行为,而接口则通过列举类型必须满足的一组方法来进行声明。如代码一就声明了一个接口类型,它调用了一个方法. 代码一:
type Phone interface {  
    call()  
}

代码二则声明了两个满足上述要求的类型。
代码二:

type NokiaPhone struct  {  
}  
  
func (nokiaPhone NokiaPhone) call()  {  
    fmt.Println("I am Nokia, I can call you!" )
}  
  
type IPhone int//不太恰当,但为了例子
  
func (iPhone IPhone) call() {  
    fmt.Println ("I am iPhone, I can call you!")
}

虽然Nokiaphone类型是个不含任何字段的结构,而IPhone类型是一个整数,但他们都满足了接口要求的call方法,因此他们都能够被赋值给phone变量。
代码三:完整代码:

type Phone interface {  
    call()  
}
type NokiaPhone struct  {  
}  
  
func (nokiaPhone NokiaPhone) call()  {  
    fmt.Println("I am Nokia, I can call you!" )
}  
  
type IPhone int//不太恰当,但为了例子
  
func (iPhone IPhone) call() {  
    fmt.Println ("I am iPhone, I can call you!")
}

func main() {  
    var phone Phone  
  
    phone = new(NokiaPhone)  
    phone.call()  
  
    phone = new(IPhone)  
    phone.call()  
  
}

3.如何测试是否已经实现该接口

写完接口后如何确认接口是否能起作用呢?
使用接口特有的断言判断来实现,

  • 语法:x.(T)
    这样的语法只适应于x是interface类型 (下文还会提及)

我们可以写一个测试函数来测试一下,
由于x.(T)只能是接口类型判断,所以传参时候,传入的是接口类型

代码四:测试代码如下:

func check(t interface{}){
  if _,ok := t.(phone);ok{
  
    fmt.Printf("true")
  }
}

4.空接口

空接口就是不包含任何方法的接口。正因为如此,所有的类型都实现了空接口

虽然空接口起不到任何作用,但是空接口在需要存储任何类型数值的时候非常有用.
代码五:

var cbs interface{}
var a int = 5
var b string = "Hello world"
// cbs可以存储任意类型的数值
cbs = a
cbs = b

5.类型判断

既然空接口可以存储任意类型,那么如何区分不同的类型?
常用的有两种方法:Comma-ok断言、switch判断

package main

import (
	"fmt"
)

// 定义一个结构体
type Student struct {
	Name string
}

// 类型断言
func main() {
    Params := make([]interface{}, 3)
	Params[0] = 88                   // 整型
	Params[1] = "咖啡色的羊驼"         // 字符串
	Params[2] = Student{Name: "cbs"} // 自定义结构体类型
	
	// Comma-ok断言
	for index, v := range Params {
		if _, ok := v.(int); ok {
			fmt.Printf("Params[%d] 是int类型 \n", index)
		} else if _, ok := v.(string); ok {
			fmt.Printf("Params[%d] 是字符串类型\n", index)
		} else if _, ok := v.(Student); ok {
			fmt.Printf("Params[%d] 是自定义结构体类型\n", index)
		} else {
			fmt.Printf("list[%d] 未知类型\n", index)
		}
	}
	
	// switch判断
	for index, v := range Params {
		switch  value := v.(type) {
        case int:
            fmt.Printf("Params[%d] 是int类型, 值:%d \n", index,value)
        case string:
            fmt.Printf("Params[%d] 是字符串类型, 值:%s\n", index,value)
        case Student:
            fmt.Printf("Params[%d] 是Person类型, 值:%s\n", index,value)
        default:
            fmt.Printf("list[%d] 未知类型\n", index)
        } 
	
	}  
}
    

6.总结

在 Go 语言中,接口(Interface)是一种类型,用于定义一组方法的集合。接口定义了方法的签名,但没有具体的实现。通过接口,可以实现多态性、代码的抽象和模块化,以及提供统一的访问方式。

以下是 Go 语言中接口的一些特点和用法:

  1. 方法集合:接口是由一组方法签名组成的集合。方法签名包括方法的名称、参数列表和返回类型。任何类型只要实现了接口中的所有方法,就被视为实现了该接口。
  2. 隐式实现:Go 语言中的接口实现是隐式的,不需要显式声明实现了某个接口。只要一个类型拥有了接口中定义的所有方法,它就被视为实现了该接口,无需显示声明。
  3. 多态性:通过接口,可以实现多态性。即使用相同的接口类型,但可以在运行时存储不同类型的值。这样可以根据具体的类型调用相应的方法,实现不同的行为。
  4. 接口组合:可以通过将多个接口组合在一起形成新的接口,以便在一个类型中同时实现多个接口的方法。
  5. 接口嵌套:接口可以嵌套在其他接口中,形成接口的继承关系。嵌套接口继承了外部接口的方法,并可以添加新的方法。
  6. 零值接口:如果一个接口没有定义任何方法,那么它被称为零值接口。任何类型都实现了零值接口,因为它没有要求实现任何方法。
  7. 空接口:空接口是一个不包含任何方法的接口,它可以表示任意类型的值。可以将任意类型的值赋给空接口变量。