Go语言中interface的两大用法详解
作者:我叫黑大帅
在 Go 语言中,interface 是一组方法的集合,它定义了一种行为规范,但不提供实现。任何类型只要实现了接口中定义的所有方法,就隐式地实现了该接口。这是 Go 实现多态和灵活设计的基础。
为什么需要 interface
interface 让你能够编写更通用、更松耦合的代码。例如,你希望一个函数可以接受多种不同类型的参数,只要它们都能“说话”,就可以定义一个 Speaker 接口,然后让不同的类型实现它。这样函数就不需要针对每种具体类型写一份代码。
interface的基本语法
type 接口名 interface {
方法名1(参数列表) 返回值列表
方法名2(参数列表) 返回值列表
// ...
}
示例:
type Writer interface {
Write(data []byte) (int, error)
}
type Stringer interface {
String() string
}Go中的interface的两大用法
interface = 方法的集合,是一套规范 / 约定。
只要一个类型实现了接口里的所有方法,它就自动实现了这个接口。
// 动物interface
type Animal interface {
Eat()
Run()
}
// 猫结构体
type Cat struct {
Name string
}
func (c Cat) Eat() {
fmt.Println(c.Name, "吃鱼")
}
func (c Cat) Run() {
fmt.Println(c.Name, "快跑")
}
// 狗结构体
type Dog struct {
Name string
}
func (d Dog) Eat() {
fmt.Println(d.Name, "啃骨头")
}
func (d Dog) Run() {
fmt.Println(d.Name, "狂奔")
}
Cat 和 Dog 都实现了 Animal 接口的全部方法 ,它们都是 Animal 类型。
基本用法
func main() {
// 定义接口变量
var animal Animal
// 把 Cat 赋值给接口
animal = Cat{Name: "小猫"}
animal.Eat() // 小猫 吃鱼
animal.Run() // 小猫 快跑
// 把 Dog 赋值给接口
animal = Dog{Name: "小狗"}
animal.Eat() // 小狗 啃骨头
animal.Run() // 小狗 狂奔
}
泛型的通用效果
// 参数是 Animal 接口:能接收所有实现了 Animal 的类型
func MyFun(a Animal) {
a.Eat()
}
func main() {
miao := Cat{Name: "小白"}
wang := Dog{Name: "旺财"}
MyFun(miao) // 小白 吃鱼
MyFun(wang) // 旺财 啃骨头
}
解耦合 : 谁都不依赖谁
现在我实现了一个第三方模块(itsdk),你不能改源码
package itsdk
// 第三方只给你一个接口:定规矩
type PayChannel interface {
Pay(amount int) string
}
// 第三方提供的功能:必须传 PayChannel 才能用
func StartPay(p PayChannel) {
result := p.Pay(100)
println(result)
}
- 只依赖一个接口
PayChannel - 不关心你的任何代码
我的代码
package main
import (
"itsdk" // 引入第三方
"strconv" // “字符串” 与 “基本数据类型” 转换的核心工具包
)
// 自己定义结构体
type MyPay struct{}
// PayChannel 目前只有 Pay 一个方法;
// 只要实现 Pay ,MyPay 就是PayChannel 类型
func (m MyPay) Pay(amount int) string {
return "支付结果:" + strconv.Itoa(amount)
}
func main() {
a := MyPay{}
itsdk.StartPay(a)
// 支付结果:100
}
- 通过实现了
Pay方法,MyPay成为PayChannel类型; - 这样才能正常使用
StartPay方法!
必须实现第三方给的接口,才能调用功能;
保证了你没遵守规矩,我不让你用我的函数
空接口 interface {}(万能类型)
// 能接收任何类型
func PrintAny(v interface{}) {
fmt.Println(v)
}
func main() {
PrintAny(100) // 100
PrintAny("hello") // hello
PrintAny(Cat{Name: "小猫"}) // 小猫 吃鱼
}
最佳实践与常见陷阱
1.接口应小而专:遵循“只做一件事”的原则。标准库中的 io.Reader、io.Writer 都是经典例子。
2.接收者类型一致性:一个类型的方法集包括值接收者和指针接收者,但接口变量能否接受该类型取决于你传递的是值还是指针。
- 如果实现方法用的是
func (t T) Method(),那么T和*T都实现了接口。 - 如果实现方法用的是
func (t *T) Method(),那么只有*T实现了接口。
3.nil 与 nil 接口:永远不要返回具体类型的 nil 指针作为 error 接口,请直接 return nil。
4.尽量使用小的接口:大接口难以实现,也会降低复用性。
5.接受接口,返回结构体:函数参数使用接口提高灵活性,返回值通常使用具体类型,避免过早抽象。
到此这篇关于Go语言中interface的两大用法详解的文章就介绍到这了,更多相关Go interface用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
