文章目录

  • 接口
  • 声明接口
  • 实现接口的条件
  • 理解类型和接口的关系
  • 接口的嵌套组合---将多个接口放在一个接口内
  • 在接口和类型之间转换
  • 空接口类型---能保存所有值的类型
  • 类型分支---批量判断空接口中变量的类型

接口

Go语言中使用组合实现对象特性的描述
对外通过接口暴露能使用的特性

Go语言的接口设计是非侵入式的,接口编写者无需知道接口被哪些类型实现。而接口实现者只需要知道实现的是什么样子的接口。
接口实现者不需要关系接口被怎样使用,调用者无需关心接口的实现细节。

概念:接口是一种类型,也是一种抽象结构,不会暴露所含数据的格式、类型和结构。

声明接口

每个接口类型由数个方法组成,格式如下:

type 接口类型名 interface{
	方法名1(参数列表1) 返回值列表1
	方法名2(参数列表2) 返回值列表2
	...
}

开发中常见接口及写法:

type Writer interface {
	Write(p []byte)(n int,err error)
}

type Stringer interface{
	String() string
}

实现接口的条件

1.接口的方法与实现接口的类型方法格式一致
2.接口中所有的方法均被实现。

package main

import (
	"fmt"
)

//定义一个数据写入器
type DataWriter interface {
	WriterData(data interface{}) error
}

//定义文件结构,用于实现DataWriter
type file struct{}

//实现DataWriter接口的WriteData()方法
func (d *file) WriterData(data interface{}) error {
	//模拟写入数据
	fmt.Println("WriteData:", data)
	return nil
}

func main() {
	//实例化file
	f := new(file)
	//声明一个DataWriter的接口
	var writer DataWriter
	//将接口赋值f,也就是*file类型
	writer = f
	//使用DataWriter接口进行数据写入
	writer.WriterData("data")
}

输出:

文心一言 golang接口调用 go语言接口文档_Go

如果函数名不一样会报错吗?

type DataWriter interface {
	WriterData(data interface{}) error
}

//定义文件结构,用于实现DataWriter
type file struct{}

//实现DataWriter接口的WriteData()方法
func (d *file) WriteData(data interface{}) error {
	//模拟写入数据
	fmt.Println("WriteData:", data)
	return nil
}

编译器会输出:

文心一言 golang接口调用 go语言接口文档_Go_02


如果方法签名不一样呢?答案是也会报错

理解类型和接口的关系

1.一个类型可以实现多个接口
看一个例子:

package main

import (
	"io"
)
//接口
type Writer interface {
	Writer(p []byte) (n int, err error)
}
type Closer interface {
	Close() error
}
type Socket struct{}

//实现接口
func (s *Socket) Writer(p []byte) (n int, err error) {
	return 0, nil
}
func (s *Socket) Close() error {
	return nil
}

//使用接口
func usingWriter(writer io.Writer) {
	writer.Write(nil)
}
func usingCloser(closer io.Closer) {
	closer.Close()
}
func main() {
	//实例化Socket
	s := new(Socket)

	usingCloser(s)
	usingCloser(s)
}

图示:

文心一言 golang接口调用 go语言接口文档_Go_03


2.多个类型可以实现相同的接口

也就是说一个接口中的方法可以由多个不同类型实现。

接口的嵌套组合—将多个接口放在一个接口内

接口和接口之间也可以嵌套组合成新的接口,只要接口的所有方法被实现,则这个接口的所有嵌套接口的方法均可以被调用。
接口嵌套组合示例:
Go语言的io包中定义了写入器(Writer)、关闭器(Closer)、和写入关闭器(WriteClose)3个接口。
实现:

package main

import (
	"io"
)

type Writer interface {
	Write(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}

type WriteCloser interface {
	Writer
	Closer
}

//声明一个设备结构
type device struct {
}

//实现io.Writer的write()方法
func (d *device) Write(p []byte) (n int, err error) {
	return 0, nil
}

//实现io.Closer的close方法
func (d *device) Close() error {
	return nil
}
func main() {
	//声明写入关闭器,并赋予device实例
	var wc io.WriteCloser = new(device)
	wc.Write(nil)
	wc.Close()

	var writeonly io.Writer = new(device)
	writeonly.Write(nil)
}

在接口和类型之间转换

Go语言中使用接口断言将接口转换成另外一个接口,也可以将接口转换成为另外的类型。接口的转换在开发中非常常见,使用也非常的频繁。

类型断言的基本格式:

t :=i.(T)
//t表示转换后的变量
//T代表转换的目标类型
//i代表接口变量

//另一种写法。
t ,ok :=i.(T)
//这种写法,如果发生接口未实现时,将会把ok置为false,t置为T类型的0值。

接口可以转换为其他接口。

接口也可以转换为其他类型。

接口在转换为其他类型时,接口内保存的实例对应的指针,而且是要转换的对应的类型指针。

空接口类型—能保存所有值的类型

将值保存到空接口

package main

import (
	"fmt"
)

//空接口
var any interface{}

func main() {
	any = 1
	fmt.Println(any)

	any = "hello"
	fmt.Println(any)
	any = false
	fmt.Println(any)
}

输出:

1
 hello
 false

从空接口获取值

var b bool = any.(bool)
	fmt.Println(b)

输出:false

注意:多个不同类型的值连续赋给空接口,空接口会存储值。但是空接口的类型会进行覆盖,取值的话只能取最后放入的那个类型的值。

比如:如果上述例子中取int型的话就会宕机:

var b int = any.(int)
	fmt.Println(b)

会出现这样的宕机内容:

panic: interface conversion: interface {} is bool, not int

空接口的值比较:用空接口保存值可以进行比较,如果两个不相等,返回false.

类型分支—批量判断空接口中变量的类型

类型分支断言的基本格式:

switch 接口变量.(type){
	case 类型1:
	case 类型2:
default:
}

示例:使用类型分支判断基本类型

package main

import (
	"fmt"
)

func printType(v interface{}) {
	switch v.(type) {
	case int:
		fmt.Println(v, "is int")
	case string:
		fmt.Println(v, "is string")
	case bool:
		fmt.Println(v, "is bool")
	}
}

func main() {
	printType(1024)
	printType("pig")

	printType(true)
}

输出:

1024 is int
 pig is string
 true is bool