为了账号安全,请及时绑定邮箱和手机立即绑定

将接口与 golang 中的类型联合

将接口与 golang 中的类型联合

Go
万千封印 2022-12-13 16:24:48
我正在尝试在 Golang 中实现一些缓存功能,但我希望它们对字符串和实现该接口的其他对象都有效Stringer。我正在尝试使用 Golang 泛型,这是我目前所拥有的:import (    "fmt")type String interface {    ~string | fmt.Stringer}然而,这给出了一个错误cannot use fmt.Stringer in union (fmt.Stringer contains methods)。有没有办法在不依赖反射或类型装箱/拆箱的情况下做到这一点?
查看完整描述

2 回答

?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

混淆可能是有道理的,因为类型参数提案建议像你的代码,但最终成为 Go 1.18 中的实现限制。

它在specs和 Go 1.18 发行说明中提到。规格是规范参考:

实现限制:一个联合(多于一个术语)不能包含预先声明的标识符comparable或指定方法的接口,或嵌入comparable或指定方法的接口。

对于为什么这没有包含在 Go 1.18 版本中,也有一些广泛的解释。tl;dr 简化了联合类型集的计算(尽管在 Go 1.18 中,类型参数的方法集也不是隐式计算的......)。

还要考虑,无论有没有这个限制,除了传递给使用反射的函数之外,您可能不会获得任何有用的东西T。要调用方法,~string | fmt.Stringer您仍然必须进行类型断言或类型切换。

请注意,如果这种约束的目的只是为了打印字符串值,您可以只使用fmt.Sprint,它使用反射。

string对于更广泛的情况,当参数可以采用(without ~) 和 等确切类型时,如 colm.anseo's answer 中的类型断言或开关工作得很好fmt.Stringer。对于近似值,~string 您无法穷尽地处理所有可能的项,因为这些类型集实际上是无限的。所以你又回到了反思。更好的实现可能是:

func StringLike(v any) string {

    // switch exact types first

    switch s := v.(type) {

    case fmt.Stringer:

        return s.String()


    case string:

        return s

    }


    // handle the remaining type set of ~string

    if r := reflect.ValueOf(v); r.Kind() == reflect.String {

        return r.String()

    }


    panic("invalid type")

}

游乐场:https://go.dev/play/p/-wzo2KPKzWZ


查看完整回答
反对 回复 2022-12-13
?
森栏

TA贡献1810条经验 获得超5个赞

泛型——理论上允许使用多种类型——在编译时选择单一的具体类型。接口允许在运行时使用多种类型。您希望同时将这两者结合起来——不幸的是,这是不可能的。


在不使用反射的情况下,最接近的方法是使用运行时类型断言:


func StringLike(v any) string {


    if s, ok := v.(string); ok {

        return s

    }


    if s, ok := v.(fmt.Stringer); ok {

        return s.String()

    }


    panic("non string invalid type")

}

https://go.dev/play/p/p4QHuT6R8yO


查看完整回答
反对 回复 2022-12-13
  • 2 回答
  • 0 关注
  • 88 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信