Go如何定义同时兼容基础类型与自定义类型的类型约束?
问题场景
需要实现通用比较逻辑:
- 支持直接传入
~int、~float32、~string这类内置有序类型,直接返回大小比较结果 - 支持自定义复合类型通过实现指定接口的方式接入比较逻辑,无需为内置类型额外编写包装结构
初始定义的类型与存在问题的实现代码如下:
type Ordered interface { ~int | ~float32 | ~string // 其余有序基础类型可自行补充 } type OrderedValue[T Ordered] interface { Value() T } func doCompare[T Ordered](a, b T) int { if a > b { return 1 } else if a < b { return -1 } return 0 } // 存在编译错误的Compare实现 func Compare[U Ordered, V OrderedValue[U], T U | V](a, b T) int { var i interface{} = a if _, ok := i.(OrderedValue[U]); ok { return doCompare(a.Value(), b.Value()) } return doCompare(a, b) }
编译时触发三类报错:
cannot embed a type parameter
a.Value undefined (type T has no field or method Value)
b.Value undefined (type T has no field or method Value)
报错根因
cannot embed a type parameter:Go泛型语法明确禁止在类型约束的联合类型中嵌入类型参数,代码中T U | V的V是泛型类型参数,直接违反语法规则。Value undefined类报错:当类型参数的约束是多个类型的联合、且联合类型无统一核心类型时,编译器仅允许访问联合所有分支共有的方法/字段,Value()是仅属于OrderedValue[U]分支的方法,未做类型断言前无法直接调用。
参考的联合切片遍历方案无法直接复用:该场景下联合的所有分支均为切片类型,存在len、索引取值这类公共核心操作,而当前场景下联合分支分别是基础值类型、带方法的接口类型,无公共核心操作,无法直接通过核心类型特性实现统一逻辑。
可行实现
不需要为内置类型编写包装结构,通过类型开关做分支处理即可满足需求,示例代码如下:
type Ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } type OrderedValue[T Ordered] interface { Value() T } func doCompare[T Ordered](a, b T) int { if a > b { return 1 } else if a < b { return -1 } return 0 } func Compare[T any](a, b T) int { switch av := any(a).(type) { // 处理实现了OrderedValue接口的自定义类型 case OrderedValue[int]: return doCompare(av.Value(), any(b).(OrderedValue[int]).Value()) case OrderedValue[int8]: return doCompare(av.Value(), any(b).(OrderedValue[int8]).Value()) case OrderedValue[int16]: return doCompare(av.Value(), any(b).(OrderedValue[int16]).Value()) case OrderedValue[int32]: return doCompare(av.Value(), any(b).(OrderedValue[int32]).Value()) case OrderedValue[int64]: return doCompare(av.Value(), any(b).(OrderedValue[int64]).Value()) case OrderedValue[uint]: return doCompare(av.Value(), any(b).(OrderedValue[uint]).Value()) case OrderedValue[uint8]: return doCompare(av.Value(), any(b).(OrderedValue[uint8]).Value()) case OrderedValue[uint16]: return doCompare(av.Value(), any(b).(OrderedValue[uint16]).Value()) case OrderedValue[uint32]: return doCompare(av.Value(), any(b).(OrderedValue[uint32]).Value()) case OrderedValue[uint64]: return doCompare(av.Value(), any(b).(OrderedValue[uint64]).Value()) case OrderedValue[uintptr]: return doCompare(av.Value(), any(b).(OrderedValue[uintptr]).Value()) case OrderedValue[float32]: return doCompare(av.Value(), any(b).(OrderedValue[float32]).Value()) case OrderedValue[float64]: return doCompare(av.Value(), any(b).(OrderedValue[float64]).Value()) case OrderedValue[string]: return doCompare(av.Value(), any(b).(OrderedValue[string]).Value()) // 处理直接传入基础有序类型的场景 case int: return doCompare(av, any(b).(int)) case int8: return doCompare(av, any(b).(int8)) case int16: return doCompare(av, any(b).(int16)) case int32: return doCompare(av, any(b).(int32)) case int64: return doCompare(av, any(b).(int64)) case uint: return doCompare(av, any(b).(uint)) case uint8: return doCompare(av, any(b).(uint8)) case uint16: return doCompare(av, any(b).(uint16)) case uint32: return doCompare(av, any(b).(uint32)) case uint64: return doCompare(av, any(b).(uint64)) case uintptr: return doCompare(av, any(b).(uintptr)) case float32: return doCompare(av, any(b).(float32)) case float64: return doCompare(av, any(b).(float64)) case string: return doCompare(av, any(b).(string)) default: panic("unsupported type for compare") } }
实现说明
- 所有内置有序类型可以直接传入Compare函数,不需要做任何包装
- 自定义类型只要实现对应底层类型的
OrderedValue[T]接口,即可直接传入Compare参与比较 - 类型分支如果觉得手写繁琐,可以通过Go代码生成自动批量生成,也可以用反射做类型判断兜底减少代码量(反射会带来少量性能损耗,普通业务场景无感知)
内容的提问来源于stack exchange,提问作者Michael Grubb
相关产品推荐
相关产品推荐

