Go 之烧脑的接口

基本定义

Go 官方对于接口的定义是一句话:An interface type is defined as a set of method signatures. 翻译过来就是,一个接口定义了一组方法的集合。这和 Java 和 PHP 的接口类似,定义一组方法而不定义方法的具体实现。但是与 Java 和 PHP 迥然不同的地方在于 Go 不需要显式的声明 implements 关键词来继承接口,一个类型只要实现了接口中的所有方法,就视作继承了该接口,是隐式实现的。来看一个基本的使用示例:

复制代码
// 定义一个平台接口,包含一个支付方法
type Platform interface {
	Pay(amount int) error
}

// 微信平台
type Wechat struct{}

func (w *Wechat) Pay(amount int) error {
	fmt.Printf("wechat amount: %d\n", amount)
	return nil
}

// 支付宝平台
// 任意值都可以实现接口,并非一定需要struct
type Alipay int

func (a Alipay) Pay(amount int) error {
	fmt.Printf("alipay amount: %d, a: %d\n", amount, a)
	return nil
}

func ExamplePlatform() {
	var (
		p Platform
		w        = Wechat{}
		a Alipay = 1
	)
	p = &w
	p.Pay(2)

	p = &a
	p.Pay(3)

	// 这种写法会报错
	// p = w
	p = a
	p.Pay(4)

	// Output:
	// wechat amount: 2
	// alipay amount: 3, a: 1
	// alipay amount: 4, a: 1
}

在这个示例中,我们定义了一个 Platform 接口和两个结构体,分别使用了值接收器和指针接收器来实现了 Platform 接口。p = w 这行代码会报错,究其原因是,对于使用指针接收器实现的接口的 Wechat,只有它的指针会实现接口,值不会实现 ;而对于值实现接口的 Alipay,指针和值都会实现接口。所以 p = a 可以正常运行。

接口嵌套

接口可以嵌套另一个接口:

复制代码
// 定义一个平台接口,包含一个支付方法
type Platform interface {
	Pay(amount int) error
	User
}

type User interface {
	Login()
	Logout()
}

// 微信平台
type Wechat struct{}

func (w *Wechat) Pay(amount int) error {
	fmt.Printf("wechat amount: %d\n", amount)
	return nil
}

func (w *Wechat) Login()  {}
func (w *Wechat) Logout() {}

此时,Wechat 即实现了 Platform 接口,也实现了 User 接口。

接口类型断言

再来看一个很复杂的例子,我们将上面的代码稍作修改,将 WechatLogin Logout 提到另一个结构中,然后使用类型断言判断 Wechat 是否实现了 User 接口:

复制代码
// 定义一个平台接口,包含一个支付方法
type Platform interface {
	Pay(amount int) error
	User
}

type User interface {
	Login()
	Logout()
}

type UserS struct {
}

func (u *UserS) Login()  {}
func (u *UserS) Logout() {}

// 微信平台
type Wechat struct {
	UserS
}

func (w *Wechat) Pay(amount int) error {
	fmt.Printf("wechat amount: %d\n", amount)
	return nil
}

func ExamplePlatform() {
	var (
		p Platform
		w = Wechat{}
	)
	p = &w
	p.Pay(2)

	// 类型断言
	_, ok := p.(User)
	fmt.Println(ok)

	// Output:
	// wechat amount: 2
	// true
}

空接口

Go 1.18 新增了一个新的变量类型:any,其定义如下:

复制代码
type any = interface{}

其实 any 就是一个空接口,对于空接口而言,它没有任何方法,所以对于任意类型的值都相当于实现了空接口,这个概念和另一个编程概念十分相似,它就是大名鼎鼎的泛型。在 Go 语言中,fmt.Println 函数的接收值正是一个 any

复制代码
func Println(a ...any) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}

使用空接口搭配类型断言,我们可以设计出一个简单的类型转换函数,它将任意类型的值转为 int:

复制代码
func ToInt(i any) int {
	switch v := i.(type) {
	case int:
		return v
	case float64:
		return int(v)
	case bool:
		if v {
			return 1
		}
		return 0
	case string:
		vint, _ := strconv.Atoi(v)
		return vint
	}

	return 0
}
相关推荐
研究司马懿18 小时前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大1 天前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰2 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘2 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤2 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto4 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto5 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室6 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题6 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo