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)
}
相关推荐
hkNaruto8 小时前
【P2P】【Go】采用go语言实现udp hole punching 打洞 传输速度测试 ping测试
golang·udp·p2p
入 梦皆星河8 小时前
go中常用的处理json的库
golang
海绵波波10710 小时前
Gin-vue-admin(2):项目初始化
vue.js·golang·gin
每天写点bug10 小时前
【go每日一题】:并发任务调度器
开发语言·后端·golang
一个不秃头的 程序员10 小时前
代码加入SFTP Go ---(小白篇5)
开发语言·后端·golang
基哥的奋斗历程10 小时前
初识Go语言
开发语言·后端·golang
ZVAyIVqt0UFji17 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡
唐墨12321 小时前
golang自定义MarshalJSON、UnmarshalJSON 原理和技巧
开发语言·后端·golang
老大白菜1 天前
FastAPI vs Go 性能对比分析
开发语言·golang·fastapi
千年死缓1 天前
golang结构体转map
开发语言·后端·golang