使用仿制药时从接口中获取基本类型

发布于 2025-02-03 17:21:06 字数 928 浏览 5 评论 0原文

我的功能无法更改,该功能看起来像foo(interface {})。在其他类型中,此功能可以采用类型[]字节,但不能服用[16]字节。我想基于仿制药来编写一个小型适配器,以增加对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[:])
    }
}

但是,如何将包含gofrsuuid.uuid接口{}转换为该基本类型[16]字节

I have a function that I cannot change, the function looks like foo(interface{}). Among some other types, this function can take a type []byte but cannot take [16]byte. I want to write a little adapter based on generics that add support for UUIDs instead of writing foo(uuid[:]), but I don't want to get hung up on specific implementations. For example, instead of

import (
    gofrsuuid "github.com/gofrs/uuid"
    googleuuid "github.com/google/uuid"
)

type AcceptedCertainTypes interface {
    int | gofrsuuid.UUID | googleuuid.UUID // | etc...
}

I want to have

type AcceptedTypes interface {
    int | ~[16]byte
}

But I have no idea how to do this. When we use certain types, it is easy to turn them into the right ones.

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[:])
    }
}

But how to convert interface{} that contains gofrsuuid.UUID to that base type [16]byte?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爺獨霸怡葒院 2025-02-10 17:21:06

您不能在工会的大约术语上具有详尽的类型开关,例如〜[16]字节,因为根据定义设置的类型是未结合的。您必须使用反射来提取阵列类型并最终重新放置它。

如果大约

〜[16]字节是联合联盟中唯一的一个大约项,则可以输入切口并在>默认 block中处理。这是基于类型参数的编译时类型安全性,因此默认 block不会使用任何意外类型运行:

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[:])
    }
}

playground: https://go.dev/play/p/_uxmwgyew5n

如果联盟中有很多tilde术语

,则不能依靠<<<<<<<<<<<<<<<<<<<<<<< >默认情况案例。如果基础类型都不同,则您可以打开Refflect.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:
        // ...
    }
}

许多相似的近似术语

类型参数无济于事,只需使用详尽地使用类型开关的所有可能类型。您可以分组您知道具有相同基础类型的类型,并使用value#convert,如上所示 - 或类型特定的方法,例如value#int()值#string() - 以类似的方式处理它们。

You can't have an exhaustive type switch on a union's approximate term like ~[16]byte, because the type set by definition is unbound. You have to use reflection to extract the array type and eventually reslice it.

Only one approximate term

If the approximate term ~[16]byte is the only one in the union, you can type-switch and handle it in the default block. This is based on the compile-time type safety of type parameters, so that default block will not run with any unexpected type:

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[:])
    }
}

Playground: https://go.dev/play/p/_uxmWGyEW5N

Many different approximate terms

If you have many tilde terms in a union, you can't rely on default case. If the underlying types are all different, you may be able to switch on 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:
        // ...
    }
}

Many similar approximate terms

Type parameters won't help much, just use any and exhaustively type-switch an all possible types. You can group types that you know have the same underlying type and use Value#Convert as shown above — or type-specific methods like Value#Int() or Value#String() —, to handle them similarly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文