Go 接口

本文介绍了Go语言中的接口概念,包括接口的声明方式,如何实现接口,接口的赋值,接口的嵌套以及空接口的使用。同时,详细讲解了类型断言在接口操作中的作用,展示了如何判断接口变量的具体类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

什么是接口

接口的声明

接口的赋值

接口的嵌套

空接口

类型断言


什么是接口

接口本身是调用方和实现方均需要遵守的一种协议,大家按照统一的方法命名参数类型和数量来协调逻辑处理的过程。

Go 语言中使用组合实现对象特性的描述。对象的内部使用结构体内嵌组合对象应该具有的特性,对外通过接口暴露能使用的特性。

Go 语言的接口设计是非侵入式的,接口编写者无须知道接口被哪些类型实现。而接口实现者只需知道实现的是什么样子的接口,但无须指明实现哪一个接口。编译器知道最终编译时使用哪个类型实现哪个接口,或者接口应该由谁来实现。

接口的声明

语法

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

说明

接口类型名:使用 type 将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加 er,如有写操作的接口叫 Writer,有字符串功能的接口叫 Stringer,有关闭功能的接口叫 Closer 等。


方法名:当方法名首字母是大写时,且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。

参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略不写,数据类型要写。

接口的方法:接口的方法在接口中只定义。具体的实现逻辑在结构体中完成。

接口的实现:实现关系在Go语言中是隐式的。两个类型之间的实现关系不需要在代码中显式地表示出来。Go语言中没有类似于 implements 的关键字。 Go编译器将自动在需要的时候检查两个类型之间的实现关系。只要结构体拥有接口里声明的所有方法,就称该结构体"实现了接口"。

接口被实现的条件:

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

示例

// 定义一个接口

type Cruder interface {
	selectList(int, int) (int, error)
	updateOne(string) (int, error)
}

// 定义一个结构体,结构体实现了接口中的所有方法,那么就表示这个结构体实现了这个接口

// 定义结构体
type Product struct {
	id           string
	name         string
	producedDate time.Time
}

// 实现方法
func (Product) selectList(pageNum int, pageSize int) (int, error) {
	return 1, nil
}

// 实现方法
func (Product) updateOne(id string) (int, error) {
	return 1, nil
}

// 使用

func testInter(c Cruder) {
	c.selectList(1, 10)
	c.updateOne("1")
}

func main() {
	var p = Product{}
	testInter(p)
}

接口的赋值

// 以上面的示例为例
func main() {
	var p Product
	var c Cruder
	c = p
}

如果 结构体实现的接口方法是指针类型,那么传值的时候就要赋值实例的地址

// 例如这个接口的实现 是 *Product
func (*Product) selectList(pageNum int, pageSize int) (int, error) {
	return 1, nil
}

// 赋值
func main() {
	var p Product
	var c Cruder
	c = &p    // 赋值的时候就要去实例的地址
}


接口的嵌套

type Cruder interface {
	selectList(int, int) (int, error)
	updateOne(string) (int, error)
}

type Producter interface {
	Cruder	// 嵌套其他的接口,表示Producter这个里面也有了Cruder的方法
	delete(string) (int, error)
}

空接口

空接口是接口类型的特殊形式,空接口没有任何方法,因此任何类型都无须实现空接口。从实现的角度看,任何值都满足这个接口的需求。因此空接口类型可以保存任何值,也可以从空接口中取出原值。

空接口类型类似于 C# 或 Java 语言中的 Object、C语言中的 void*、C++ 中的 std::any。在泛型和模板出现前,空接口是一种非常灵活的数据抽象保存和使用的方法。

空接口的内部实现保存了对象的类型和指针。使用空接口保存一个数据的过程会比直接用数据对应类型的变量保存稍慢。因此在开发中,应在需要的地方使用空接口,而不是在所有地方使用空接口

空接口的定义使用 interface{}

var i interface{}

示例1

var i interface{}
i = 1
fmt.Println(i) // 1
i = "hello"
fmt.Println(i) // hello
i = false
fmt.Println(i) // false

示例2

func testNilInter(a interface{}) {
	fmt.Println(a)
}

func main() {
	testNilInter(1)
	testNilInter("hello")
	testNilInter(false)
}

类型断言

func test1(i interface{}) {
	// 判断 i 是否是 int 类型,如果是 ok 为true,把 i 赋值给 v
	if v, ok := i.(int); ok {
		fmt.Println("int = ", v)
	} else if v, ok := i.(float32); ok {
		fmt.Println("float32 = ", v)
	} else if v, ok := i.(User); ok { // 自定义类型
		fmt.Println("User = ", v)
	}
}

func main() {
	var i User
	test(i)
}
func test2(i interface{}) {
	switch i.(type) {
	case int:
		fmt.Println("int = ", i)
	case float32:
		fmt.Println("float32 = ", i)
	case User:
		fmt.Println("User = ", i)
	}
}

func main() {
	var i User
	test(i)
}

全套教程地址:Golang全套教程

### Go语言中接口的定义和使用 在Go语言中,接口(interface)是一种抽象类型,它定义了一组方法的集合,但不提供这些方法的具体实现。接口的主要作用是通过定义一组行为规范,使得不同类型的对象可以通过实现这些行为来满足接口的要求。 #### 1. 接口的定义 接口的定义格式如下: ```go type 接口类型名 interface { 方法名1(参数列表1) 返回值列表1 方法名2(参数列表2) 返回值列表2 ... } ``` 接口的命名习惯通常以`er`结尾,例如`Reader`、`Writer`等[^3]。接口中的方法只有声明,没有具体实现,并且方法的参数列表和返回值列表可以省略变量名[^4]。 #### 2. 实现接口的条件 在Go语言中,一个类型只要实现了接口中定义的所有方法,就认为该类型实现了这个接口,而无需显式声明实现了哪个接口。这种机制被称为结构化类型系统(Structural Typing)。例如,如果一个类型的方法集中包含接口定义的所有方法签名(名称、参数列表和返回值列表一致),则该类型自动实现该接口[^4]。 #### 3. 接口的使用示例 以下是一个简单的示例,展示如何定义和使用接口: ```go package main import "fmt" // 定义接口 type Phone interface { call() } // 定义NokiaPhone类型并实现call方法 type NokiaPhone struct{} func (nokia NokiaPhone) call() { fmt.Println("I am Nokia, I can call you!") } // 定义IPhone类型并实现call方法 type IPHONE struct{} func (iphone IPHONE) call() { fmt.Println("I am iPhone, I can call you!") } func main() { var phone Phone // 将NokiaPhone赋值给Phone接口 phone = new(NokiaPhone) phone.call() // 将IPhone赋值给Phone接口 phone = new(IPHONE) phone.call() } ``` 运行结果为: ``` I am Nokia, I can call you! I am iPhone, I can call you! ``` 在此示例中,`Phone`接口定义了一个`call`方法,`NokiaPhone`和`IPHONE`两个类型分别实现了该方法。通过将不同类型的对象赋值给`Phone`接口变量,可以调用它们各自实现的`call`方法[^5]。 #### 4. 接口的多态性 接口支持多态性,这意味着可以通过接口变量调用不同类型的对象所实现的方法。例如,在上述代码中,`phone`变量可以指向`NokiaPhone`或`IPHONE`类型的对象,并调用它们各自的`call`方法。 #### 5. 空接口接口`interface{}`表示没有任何方法的接口,它可以存储任何类型的值。因此,空接口常被用作通用数据容器[^4]。 ```go var value interface{} = 42 fmt.Println(value) value = "Hello, World!" fmt.Println(value) ``` #### 6. 类型断言与接口转换 通过类型断言,可以从接口中提取具体的类型信息。例如: ```go value := "Hello, World!" if str, ok := value.(string); ok { fmt.Println("Value is a string:", str) } else { fmt.Println("Value is not a string") } ``` #### 7. 接口的嵌套 接口可以匿名嵌套其他接口,形成更复杂的接口定义。例如: ```go type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type ReadWriter interface { Reader Writer } ``` 在此示例中,`ReadWriter`接口包含了`Reader`和`Writer`接口的所有方法。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7 号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值