使用泛型时从接口获取基类型

我有一个我无法更改的功能,该功能看起来像foo(interface{}). 在其他一些类型中,此函数可以采用类型[]byte但不能采用[16]byte. 我想写一个基于泛型的小适配器来添加对 UUID 的支持而不是编写foo(uuid[:]). 但我不想挂在特定的实现上。例如,而不是


import (

    gofrsuuid "github.com/gofrs/uuid"

    googleuuid "github.com/google/uuid"

)


type AcceptedCertainTypes interface {

    int | gofrsuuid.UUID | googleuuid.UUID // | etc...

}

我希望有


type AcceptedTypes interface {

    int | ~[16]byte

}

但我不知道该怎么做。当我们使用某些类型时,很容易将它们变成正确的类型。


func rewrittenFoo[T AcceptedCertainTypes](val T) {

    var t interface{} = *new(T)

    switch t.(type) {

    case gofrsuuid.UUID:

        k := val.(gofrsuuid.UUID)

        foo(k[:])

    case googleuuid.UUID:

        k := val.(googleuuid.UUID)

        foo(k[:])

    }

}

但是如何将interface{}contains转换gofrsuuid.UUID为该基本类型[16]byte?


慕村9548890
浏览 73回答 1
1回答

MMMHUHU

您不能对联合的近似项(如 )进行详尽的类型转换~[16]byte,因为定义设置的类型是未绑定的。您必须使用反射来提取数组类型并最终将其重新切片。只有一个近似项如果近似项~[16]byte在联合中是唯一的,你可以在default块中进行类型转换和处理。这是基于类型参数的编译时类型安全性,因此该default块不会以任何意外类型运行:func rewrittenFoo[T int | ~[16]byte](val T) {    switch t := any(val).(type) {    // handle all non-approximate type cases first    case int:        foo(t) // t is int    // this will be all other types in T's type set that are not int    // so effectively ~[16]byte    default:        v := reflect.ValueOf(t).Convert(reflect.TypeOf([16]byte{})).Interface().([16]byte)        foo(v[:])    }}游乐场:https ://go.dev/play/p/_uxmWGyEW5N许多不同的近似项如果联合中有很多代字号,则不能依赖default大小写。如果底层类型都不同,您可以打开reflect.Kind:func rewrittenFoo[T int | ~float64 | ~[16]byte](val T) {    // handle all non-approximate type cases first    switch t := any(val).(type) {    case int:        foo(t)    }    switch reflect.TypeOf(val).Kind() {    case reflect.Float:        // ...    case reflect.Array:        // ...    }}许多相似的近似项类型参数不会有太大帮助,只需使用any并详尽地类型切换所有可能的类型。您可以将您知道具有相同基础类型的类型分组,并使用Value#Convert如上所示 - 或特定于类型的方法(如Value#Int()或Value#String()-)来类似地处理它们。
打开App,查看更多内容
随时随地看视频慕课网APP