赞助
本课程由弘舟职擎赞助支持, 此网站提供自动化评测、AI模拟笔试和面试工具, 后期会有更多更强大的工具开发出来,请百度搜索'弘舟职擎模拟面试', 请大家关注和支持, 谢谢!
cmp.Ordered 与 comparable的对比
解决手写和遗忘地狱
上期结尾我留了个坑------comparable 只管判等、不管比大小。这期就把比大小的坑填上
golang
type MyComparable interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint8 | ~int32 | ~string | float64
}
import cmp
func Max[T com.Ordered](a, b T) T {}
对比
| 能力 | comparable |
cmp.Ordered |
|---|---|---|
==/ != |
✅ | ✅ |
| 结构体/指针 | ✅ | ❌ |
| 字符串、数字 | ✅ | ✅ |
com.Ordered自定义struct怎么支持排序?
golang
type User struct{
Name string
Age int
}
func Less(a,b User) bool {
if a.Age <= b.Age {
return true
}
return false
}
func SortUser[T any](users []T, less func(a, b T) bool) {
///
}
类型怎么推断的?
实参类型推断
golang
func Index[T comparable](haystack []T, needle T) int {}
Index([]int{1, 2, 3}, 2) // 返回1
// []T => []int => T = int
范型约束推断
golang
type SliceConstraint[E any] interface{
~[]E
}
func First[E any, S SliceConstraint[E]](s S) E {}
First([]int{1, 2, 3}) // []int -> S
~[]E - []int => E = int
无法隐式推断
golang
func New[T any]() *T{
return new(T)
}
p := New[int]()
// p := New()
常量未类型化
golang
type SmallInt interface{~uint8}
func SmallMax[T SmallInt](a, b T) T{...}
SmallMax(5, 10) // 编译错误, 5=> int
// 1. 强制类型转换
SmallMax(uint(5), uint(10))
// 2. 指定类型实参调用
SmallMax[uint8](5, 10)
Go 特意不做
Java /C Sharp 类型擦除 VS Go单态、Cpp 模板实例化
为什么这么克制?三个字:可读性。泛型方法语法复杂、推断负担重;运算符重载破坏可读性;类型特化让编译模型复杂、代码膨胀。最后补一个关键背景:Java 用类型擦除,编译后变 Object,运行时强转,基本类型要装箱;Go 用单态化,给每个类型参数生成一份特化代码,运行时零转换零装箱,代价是代码体积可能膨胀。这也解释了为什么 Go 不做 C++ 那套------单态化已经承担了按类型生成代码的成本。记四个不做:泛型方法、可变类型参数、运算符重载、类型特化/元编程,再加没有方法链语法。
四不做
不支持范型方法
golang
type Stack[T any] struct {items []T}
func (s *Stack[T]) Push(v T) {} // 支持
// func (s *Stack[T]) Map[U any](f func(T) U) []U {} // 不支持
// Java : public <U> Box<U> map(...)
不支持可变类型参数 + 运算符重载
没有类型特化 / 模板元编程(C++特性)
cpp
// C++: 全特化, bool单独一份实现
template <> struct Printer<bool> {....}
// go只有一份通用实现, 所有类型共用
没有方法链语法糖
Java
// Java: box.map(...).map(...).count()
// Go: 只能独立函数调用
完整合集请看
