2 回答

TA貢獻1946條經驗 獲得超4個贊
順便說一句,已經有一個用于排序的庫
https://pkg.go.dev/golang.org/x/exp/slices#Sort
1. 您可以使用泛型創建接口,然后為其鍵入斷言。
例子:
type Lesser[T SupportedType] interface {
Less(T) bool
}
type Vec[T SupportedType] []T
func (vec Vec[T]) Less(a, b int) bool {
return any(vec[a]).(Lesser[T]).Less(vec[b])
}
func main() {
vs := Vec[String]([]String{"a", "b", "c", "d", "e"})
vb := Vec[Bool]([]Bool{false, true})
fmt.Println(vs.Less(3, 1))
fmt.Println(vb.Less(0, 1))
}
2.可以保存Vec上的類型。
例子:
type Lesser[T SupportedType] interface {
Less(T) bool
}
type Vec[T SupportedType, L Lesser[T]] []T
func (vec Vec[T, L]) Less(a, b int) bool {
return any(vec[a]).(L).Less(vec[b])
}
func main() {
vs := Vec[String, String]([]String{"a", "b", "c", "d", "e"})
fmt.Println(vs.Less(3, 1))
}
3.嵌套類型約束
謝謝@blackgreen
例子 :
type SupportedType interface {
Int8 | Time | Bool | String
}
type Lesser[T SupportedType] interface {
Less(T) bool
}
type Vec[T interface {
SupportedType
Lesser[T]
}] []T
func (vec Vec[T]) Less(a, b int) bool {
return vec[a].Less(vec[b])
}
func main() {
vs := Vec[String]([]String{"a", "b", "c", "d", "e"})
fmt.Println(vs.Less(3, 1))
}
基準:
benchmark 1 : 28093368 36.52 ns/op 16 B/op 1 allocs/op
benchmark 2 : 164784321 7.231 ns/op 0 B/op 0 allocs/op
benchmark 3 : 212480662 5.733 ns/op 0 B/op 0 allocs/op
Embedding a container inside type specific structs:
benchmark 4 : 211429621 5.720 ns/op 0 B/op 0 allocs/op
哪一個最適合您取決于您。但 IMO 3 號是最好的。

TA貢獻2051條經驗 獲得超10個贊
就我個人而言,我認為最好不要在聯合中包含許多彼此無關的類型,因為它們不會共享許多通用操作,并且您最終會編寫特定于類型的代碼。那么使用泛型的意義何在……?
無論如何,可能的策略取決于SupportedType約束類型集中包含的內容,以及您希望對這些內容執行的操作:
只有確切的類型,沒有方法
使用類型開關T并運行任何對具體類型有意義的操作。當方法實現僅使用 type 的一個值時,這種方法效果最好T,因為您可以直接使用 switch guard ( v := any(vec[a]).(type)) 中的變量。當您T在 switch guard 中的值旁邊有更多值時,它就不再漂亮了,因為您必須單獨轉換和斷言所有這些值:
func (vec Vec[T]) Less(a, b int) bool {
switch v := any(vec[a]).(type) {
case int64:
return v < any(vec[b]).(int64)
case time.Time:
return v.Before(any(vec[b]).(time.Time))
// more cases...
}
return false
}
用方法
參數化包含方法的接口并將其約束T為支持的類型。然后將Vector類型參數約束為兩者。這個的優點是確保Vector不能使用您忘記實現Less(T) bool的類型實例化并擺脫類型斷言,否則可能會在運行時出現恐慌。
type Lesser[T SupportedType] interface {
Less(T) bool
}
type Vec[T interface { SupportedType; Lesser[T] }] []T
func (vec Vec[T]) Less(a, b int) bool {
return vec[a].Less(vec[b])
}
使用方法和預先聲明的類型
不可能的??紤]以下:
type SupportedTypes interface {
// exact predeclared types
int | string
}
type Lesser[T SupportedTypes] interface {
Less(T) bool
}
約束Lesser有一個空類型集,因為既int不能也string不能有方法。所以在這里你回到了“精確類型和無方法”的情況。
具有近似類型 ( ~T)
將上面的約束條件改成近似類型:
type SupportedTypes interface {
// approximate types
~int | ~string
}
type Lesser[T SupportedTypes] interface {
Less(T) bool
}
類型開關不是一個選項,因為case ~int:它不合法。約束上存在的方法會阻止您使用預先聲明的類型進行實例化:
Vector[MyInt8]{} // ok when MyInt8 implements Lesser
Vector[int8] // doesn't compile, int8 can't implement Lesser
所以我看到的選項是:
強制客戶端代碼使用定義的類型,在許多情況下這可能很好
將約束的范圍縮小到支持相同操作的類型
反射(用于查看性能損失是否對您來說太多的基準),但反射實際上無法找到基礎類型,因此您只能使用reflect.Kindor進行一些黑客攻擊CanConvert。
當/如果該提案通過時,這可能會改善并可能勝過其他選項。
- 2 回答
- 0 關注
- 110 瀏覽
添加回答
舉報