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
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
- 2 回答
- 0 关注
- 88 浏览
添加回答
举报