Golang:通用结构体实现与通用接口不匹配。

huangapple go评论82阅读模式
英文:

Golang: Genric struct implement does not match generic interface

问题

我正在尝试使用Go泛型,并遇到了这个问题。为什么Schedule不能匹配any

代码

func demo(m Model[any]) Model[any] {
	return m
}

type Model[M any] interface {
	FindOne(db *gorm.DB, conds ...any) (m M)
}

type DbOperations[M any] struct{}

func (d DbOperations[M]) FindOne(db *gorm.DB, conds ...any) (m M) {
	res := db.First(&m, conds)
	if res.Error != nil {
		return m
	}
	return m
}


// 由于这个函数,程序无法编译通过
func a() {
	m := DbOperations[Schedule]{}
	get(m) // <= 错误发生在这里
}

错误信息

../models/operations.go:103:6: 无法将类型为DbOperations[Schedule]的变量m用作get函数的Model[any]类型参数:
	DbOperations[Schedule]未实现Model[any]接口(FindOne方法类型不正确)
		具有FindOne(db *gorm.DB, conds ...any) (m Schedule)
		期望FindOne(db *gorm.DB, conds ...any) any
英文:

I am experimenting with go generics, and I have encountered this issue. Why is Schedule not matching any?

Code

func demo(m Model[any]) Model[any] {
	return m
}

type Model[M any] interface {
	FindOne(db *gorm.DB, conds ...any) (m M)
}

type DbOperations[M any] struct{}

func (d DbOperations[M]) FindOne(db *gorm.DB, conds ...any) (m M) {
	res := db.First(&m, conds)
	if res.Error != nil {
		return m
	}
	return m
}


// the program does not compile because of this function
func a() {
	m := DbOperations[Schedule]{}
	get(m) // <= error occurs here
}

Error message

../models/operations.go:103:6: cannot use m (variable of type DbOperations[Schedule]) as type Model[any] in argument to get:
	DbOperations[Schedule] does not implement Model[any] (wrong type for FindOne method)
		have FindOne(db *gorm.DB, conds ...any) (m Schedule)
		want FindOne(db *gorm.DB, conds ...any) any

答案1

得分: 1

Go语言通常要求你明确指定你使用的类型,并且通常不会自动为你转换变量的类型。所以这段代码不起作用,因为Model[any](也就是Model[interface{}])和Model[Schedule]不是相同的类型。(更多细节如下)

你可以尝试将get函数改为泛型函数:

func get[T any](m Model[T]) Model[T] {
	return m
}

然后在调用函数时指定类型:

func a() {
	m := DbOperations[Schedule]{}
	get[Schedule](m)
}

详细说明

Model[any] != Model[SomeType]的原因与你不能将字符串切片传递给接受any切片参数的函数相同:

[]interface{}切片与[]Schedule切片具有不同的内存布局。同样,Model[T]在内存中的布局与Model[any]也不同。Go语言希望你自己完成它们之间的转换工作。(总结自官方解释这里的Stack Overflow回答)

英文:

The go language usually requires you to be explicit about the types you're using, and generally does not automatically cast variables for you. So this doesn't work because Model[any] (aka Model[interface{}]) and Model[Schedule] are not the same types. (more details below)

What you could do instead, is also make get a generic func:

func get[T any](m Model[T]) Model[T] {
	return m
}

and then indicate what the type is when you call the func:

func a() {
	m := DbOperations[Schedule]{}
	get[Schedule](m)
}

Details

Model[any] != Model[SomeType] for the same reason why you can't pass a string slice to a func that takes an any slice parameter:

A []interface{} slice has a different memory layout than a []Schedule slice. Similarly, a Model[T] is laid out in memory differently than a Model[any]. Go expects you to do the work of converting them. (summarizing the official explanation and SO answers here)

huangapple
  • 本文由 发表于 2022年12月27日 10:01:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/74925209.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定