如何使用泛型将接口转换为指定类型

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

How to transfer interface to specified type by using generic

问题

这是一个声明接口和实现接口的多个结构体的代码示例。

type DataInterface interface {
	Get(string) string
}

type DataA struct {
	d map[string]string
}

func (d *DataA) Get(key string) string {
	return d.d[key]
}

func (d *DataA) GetId() string {
	return d.Get("id")
}

type DataB struct {
	d map[string]string
}

func (d *DataB) Get(key string) string {
	return d.d[key]
}

func (d *DataB) GetFile() string {
	return d.Get("file")
}

type DataC...

还包括`DataC,D,E...`

我将把这些`DataX`结构体的实例存储在`type DataSlice []DataInterface`

现在如果我想获取`DataX`可以这样做

```go
type DataSlice []DataInterface

func (d DataSlice) GetA() []*DataA {
	var ret []*DataA
	for _, di := range d {
		if v, ok := di.(*DataA); ok {
			ret = append(ret, v)
		}
	}
	return ret
}

func (d DataSlice) GetB() []*DataB {
	var ret []*DataB
	for _, di := range d {
		if v, ok := di.(*DataB); ok {
			ret = append(ret, v)
		}
	}
	return ret
}

func (d DataSlice) GetC() .....

显然,这里有很多重复的代码:

var ret []*DataX
for _, di := range d {
	if v, ok := di.(*DataX); ok {
		ret = append(ret, v)
	}
}

因此,我考虑使用泛型来解决这个问题,然后定义了这个函数:

func GetDataX[T any] (d DataInterface) *T {
	return d.(*T)
}

但是出现了错误:Impossible type assertion: '*T' does not implement 'DataInterface'

所以,我想知道这种方式真的不可能吗?还是可以通过其他方式完成?

英文:

There is an Interface declare and many structs that implement it

type DataInterface interface {
Get(string) string
}
type DataA struct {
d map[string]string
}
func (d *DataA) Get(key string) string {
return d.d[key]
}
func (d *DataA) GetId() string {
return d.Get("id")
}
type DataB struct {
d map[string]string
}
func (d *DataB) Get(key string) string {
return d.d[key]
}
func (d *DataB) GetFile() string {
return d.Get("file")
}
type DataC...

Also includes DataC,D,E...

and I will store these DataX structs instance into a type DataSlice []DataInterface

Now, If I want to get DataX , I can do this:

type DataSlice []DataInterface
func (d DataSlice) GetA() []*DataA {
var ret []*DataA
for _, di := range d {
if v, ok := di.(*DataA); ok {
ret = append(ret, v)
}
}
return ret
}
func (d DataSlice) GetB() []*DataB {
var ret []*DataB
for _, di := range d {
if v, ok := di.(*DataB); ok {
ret = append(ret, v)
}
}
return ret
}
func (d DataSlice) GetC() .....

Obviously there's a lot of repetitive code here:

var ret []*DataX
for _, di := range d {
if v, ok := di.(*DataX); ok {
ret = append(ret, v)
}
}

So I think about that I can use generic to slove this, then I define this function:

func GetDataX[T any] (d DataInterface) *T {
return d.(*T)
}

but got error: Impossible type assertion: '*T' does not implement 'DataInterface

So, I want to know is this way really impossible? Or it could be completed by the other way?

答案1

得分: 1

你应该能够使用以下代码来满足你的需求:

package main

import "fmt"

// 接口
type DataInterface interface {
	Get(string) string
}

// 实现接口的结构体
type DataA struct {
	d map[string]string
}

func (d DataA) Get(key string) string {
	return d.d[key]
}

type DataB struct {
	d map[string]string
}

func (d DataB) Get(key string) string {
	return d.d[key]
}

type DataSlice []DataInterface

func GetDataX[T any](d DataInterface) T {
	return d.(T)
}

func main() {
	a := DataA{map[string]string{"a": "1"}}
	b := DataB{map[string]string{"b": "2"}}

	ds := DataSlice{a, b}

	for _, v := range ds {
		if value, ok := v.(DataA); ok {
			fmt.Printf("A\t%q\n", GetDataX[DataA](value))
			continue
		}

		if value, ok := v.(DataB); ok {
			fmt.Printf("B\t%q\n", GetDataX[DataB](value))
			continue
		}

		// 在这里添加未知类型的处理逻辑
	}
}

首先,我简化了代码,只考虑了DataADataB结构体。然后,我将指针接收器更改为值接收器,因为你不会更改传递给方法的实际实例的状态。由于这个改变,GetDataX成功工作,你可以获取所有类似结构体的信息。

如果这解决了你的问题,或者你需要其他帮助,请告诉我,谢谢!

英文:

You should be able to handle your needs with the following code:

package main

import "fmt"

// interface
type DataInterface interface {
	Get(string) string
}

// struct implementing the interface
type DataA struct {
	d map[string]string
}

func (d DataA) Get(key string) string {
	return d.d[key]
}

type DataB struct {
	d map[string]string
}

func (d DataB) Get(key string) string {
	return d.d[key]
}

type DataSlice []DataInterface

func GetDataX[T any](d DataInterface) T {
	return d.(T)
}

func main() {
	a := DataA{map[string]string{"a": "1"}}
	b := DataB{map[string]string{"b": "2"}}

	ds := DataSlice{a, b}

	for _, v := range ds {
		if value, ok := v.(DataA); ok {
			fmt.Printf("A\t%q\n", GetDataX[DataA](value))
			continue
		}

		if value, ok := v.(DataB); ok {
			fmt.Printf("B\t%q\n", GetDataX[DataB](value))
			continue
		}

		// add unknown type handling logic here
	}
}

First, I simplified the code to take into consideration only the DataA and DataB structs. Then, I changed the pointer receivers to value receivers as you're not going to change the state of the actual instance passed to the methods. Thanks to this change the GetDataX works successfully and you're able to get the info for all of your similar structs.

Let me know if this solves your issues or if you need something else, thanks!

huangapple
  • 本文由 发表于 2023年2月14日 19:20:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75447075.html
匿名

发表评论

匿名网友

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

确定