go语言函数/方法入参对象方法 接口interface约束示例

go语言使用泛型接口约束可以约束指定的对象参数 必须具备指定的方法 或者必须实现了指定的接口 1个或者多个接口(通过接口继承实现), 这个在面向api的接口编程中应用非常广泛,也非常实用,废话不多说,直接上代码:

泛型约束 接口 方法 接口继承 示例代码

Go 复制代码
//文件名 person.go
package genricargs

import "fmt"

// 泛型接口约束方法/函数形参,可以约束形参对象必须拥有指定的方法才能调用,
// 如 func SpeechDemo2[T interface {Speech() string; Exam()}](people T)
// 形参方法约束如果有多个可以每个一行或者在当行使用 分号 ; 隔开
// 这里的[T interface {Speech() string; Exam()}]约束的是 T中的方法,只要T中有这里指定的方法即可,
// 如果 T后面跟的 interface{ 方法定义1,方法定义2} 这表示T必须具备指定的方法, 如 [T interface {Speech() string; Exam()}]
// 如果 T后面跟的是接口,则说明T必须是实现指定的接口的对象, 如  [T Ability]
// 如果需要约束某个对象必须具备多个接口,则可以是继承的方式创建一个新的接口 然后继承需要约束的接口, 如 [T AB] 这里的AB就继承了2个接口 见后面代码

// 定义对象 用来存放数据
type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

// 定义Ability能力接口
type Ability interface {
	Speech() string //演讲方法
	Swim()          //游泳方法
}

// 为对象Person实现Ability接口
func (p *Person) Speech() string {
	return fmt.Sprintf("%v正在演讲", p.Name)
}
func (p *Person) Swim() {
	fmt.Printf("%v正在游泳\n", p.Name)
}

// Person的其他普通方法
func (p *Person) Exam() {
	fmt.Printf("%v正在考试\n", p.Name)
}

// 演讲测试
func SpeechDemo[T interface {
	Speech() string
	Swim()
}](people T) {
	str := people.Speech() // 因为T约束了这个people必须具备Speech这个方法,所以这里才可以直接调用
	fmt.Println(str)
	people.Swim()
}

// 约束people必须是拥有 Speech()和Exam()方法的对象,
func SpeechDemo2[T interface {
	Speech() string
	Exam()
}](people T) {
	str := people.Speech() // 因为T约束了这个people必须具备Speech这个方法,所以这里才可以直接调用
	fmt.Println(str)
	people.Exam()
}

// 这个当前的Person对象中没有Flight()方法, 调用直接编译错误
func SpeechDemo3[T interface {
	Speech() string
	Flight()
}](people T) {
	str := people.Speech() // 因为T约束了这个people必须具备Speech这个方法,所以这里才可以直接调用
	fmt.Println(str)
	people.Flight()
}

// 泛型参数直接约束接口, 当然这里的接口可以是多个 使用|分隔即可 ,如 [T Aaa| Bbb ]表示T必须是实现了Aaa或者Bbb
func SpeechDemo4[T Ability](people T) {
	str := people.Speech() // 因为T约束了这个people必须具备Speech这个方法,所以这里才可以直接调用
	fmt.Println(str)
	people.Swim()
	// people.Flight() //这行代码 直接编译错误 因为Ability接口中没有这个方法
}

type Bbb interface {
	Flight()
}

// 继承Ability和Bbb接口
type AB interface {
	Ability
	Bbb
}

// 这里使用了接口继承的方式来约束这里的people必须实现了 Ability接口和Bbb接口
func SpeechDemo5[T AB](people T) {
	str := people.Speech() // 因为T约束了这个people必须具备Speech这个方法,所以这里才可以直接调用
	fmt.Println(str)
	people.Swim()
	people.Flight()
}

单元测试用例

Go 复制代码
// person_test.go
package genricargs

import (
	"testing"
)

// 单元测试用例
// TestXxx和 ExampleXxx使用示例
// 这2种方法的区别在于Test需要带上参数 t *testing.T 而ExampleXxx则不需要, 带参数的TestXxx可以调用 t里面的一系列方法
// 他们都可以使用Output来指定期望的输出
// testing官方手册  https://pkg.go.dev/testing@go1.22.3
// 测试运行命令
// go test -run "        # Run all tests.
// go test -run Foo       # Run top-level tests matching "Foo", such as "TestFooBar".
// go test -run Foo/A=    # For top-level tests matching "Foo", run subtests matching "A=".
// go test -run /A=1      # For all top-level tests, run subtests matching "A=1".
// go test -fuzz FuzzFoo  # Fuzz the target matching "FuzzFoo"
//
// 使用 TestXxx语法进行测试
func TestSpeechDemo(t *testing.T) {
	p1 := &Person{Name: "John", Age: 18}
	SpeechDemo(p1)  // 这里需要自己判断测试是否通过 如果未通过使用 t.Fatalf来格式化输出异常信息(或者函数抛异常也会是失败), 否则使用 t.Logf
	t.Fatal("测试失败") //直接指定这个测试是失败的 这时就会输出所有的控制台结果 包括被测试对象中使用fmt.Print打印的结果
	t.Log("abc ok")

	// 点击函数上方的 run test 这个会输出以下信息
	// go test -timeout 30s -run ^TestSpeechDemo$ tekin.cn/golearn/src/interface/genric_args

	// John正在演讲
	// John正在游泳
	// --- FAIL: TestSpeechDemo (0.00s)
	//
	//	/xxx/golang_learn_mod/src/interface/genric_args/person_test.go:29: 测试失败
	//
	// FAIL
	// FAIL	tekin.cn/golearn/src/interface/genric_args	0.281s
	// FAIL
}

// 使用 ExampleXxx方法进行测试
func ExampleSpeechDemo2() {
	p := &Person{Name: "Alex", Age: 20}
	SpeechDemo2(p)
	// output:Alex正在演讲
	// Alex正在考试
}

func ExampleSpeechDemo3(t *testing.T) {
	// p := &Person{Name: "Alex", Age: 20}
	// SpeechDemo3(p) //这里直接报语法错误 无法编译 因为 参数p缺少方法 Flight
	// output: T (type *Person) does not satisfy interface{Flight(); Speech() string} (missing method Flight)
}
相关推荐
007php0073 小时前
某游戏大厂 Java 面试题深度解析(四)
java·开发语言·python·面试·职场和发展·golang·php
꒰ঌ 安卓开发໒꒱5 小时前
Go高并发在企业级项目中的实战应用:数据库访问与GIN+GORM深度实践
数据库·golang·gin
请你喝好果汁6416 小时前
python入门到编程第三章
golang
数据知道8 小时前
Go语言设计模式:抽象工厂模式详解
设计模式·golang·抽象工厂模式·go语言
数据知道9 小时前
Go语言设计模式:组合模式详解
设计模式·golang·组合模式·go语言
周杰伦_Jay12 小时前
【网络编程、架构设计与海量数据处理】网络编程是数据流转的血管,架构设计是系统扩展的骨架,海量数据处理是业务增长的基石。
网络·golang·实时互动·云计算·腾讯云·语音识别
岁忧14 小时前
Go channel 的核心概念、操作语义、设计模式和实践要点
网络·设计模式·golang
Tony Bai17 小时前
从 Python 到 Go:我们失去了什么,又得到了什么?
开发语言·后端·python·golang
雪域迷影1 天前
Go语言中通过get请求获取api.open-meteo.com网站的天气数据
开发语言·后端·http·golang·get
数据知道1 天前
Go语言设计模式:适配器模式详解
设计模式·golang·建造者模式