Home  >  Article  >  Backend Development  >  How to convert an interface to a specified type using generics

How to convert an interface to a specified type using generics

WBOY
WBOYforward
2024-02-06 08:25:11955browse

How to convert an interface to a specified type using generics

Question content

There is an interface declaration and many structures 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...

I will store these datax struct instances into 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 is a lot of duplicate code here:

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

So I thought I could use generics to solve this problem, then I defined this function:

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

But an error occurred: impossible type assertion: '*t' does not implement 'datainterface

So I want to know is this really impossible? Or can it be done some other way?


Correct answer


You should be able to use the following code to meet your needs:

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 only consider the dataa and datab structures. I then changed the Pointer Receiver to a Value Receiver since you are not changing the state of the actual instance passed to the method. Because of this change, getdatax works successfully and you can get all the information for similar structures.

If this solves your problem or you need something else, please let me know, thank you!

The above is the detailed content of How to convert an interface to a specified type using generics. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete