在 Go 1.18 及更早版本中,用作映射鍵的類型需要預先聲明的可比較約束。此約束可確保類型支援 == 和 != 運算符,並且在使用這些運算符時不會出現恐慌。
但是,此約束並不總是適合可用作映射鍵的類型。例如,以下程式碼定義了一個通用鍊錶:
type List[X any] interface { isList() } type Cons[X any] struct { Data X Next List[X] } func (Cons[X]) isList() {} type Nil[X any] struct{} func (Nil[X]) isList() {}
此程式碼定義了一個 List 接口,該介面由兩種類型實作:Cons 和 Nil。 Cons 類型表示非空列表,而 Nil 類型表示空列表。
以下程式碼使用 List 介面建立清單到字串的對應:
type List[X any] interface { isList() } func main() { x := Cons[int]{5, Nil[int]{}} m := map[List[int]]string{} m[x] = "Hi" // succeeds fmt.Println(m[x]) // prints "Hi" }
這段程式碼將成功編譯並執行。但是,如果我們嘗試在 Cons 類型上使用方法,則會收到編譯器錯誤:
type List[X any] interface { isList() } func main() { x := Cons[int]{5, Nil[int]{}} fmt.Println(id(x)) // error: Cons[int] does not implement comparable }
錯誤訊息表示 Cons[int] 類型沒有實作可比較約束。這是因為 Cons 類型有一個 List[int] 類型的字段,而 List[int] 介面沒有實現可比較的約束。
解決此問題的一個可能的解決方案是使用較弱的類型限制。例如,我們可以使用以下約束:
type List[X any] interface { isList() Comparable() bool }
此約束允許我們使用 Cons 類型作為映射鍵,即使它沒有實現類似的約束。
可比較約束是映射鍵的正確包羅萬象的約束。根據 Go 規範可比較的所有類型,即使比較可能在運行時發生恐慌,也可以滿足可比較約束。您的程式碼將在 1.20 中按預期進行編譯。
這最終修復了先前的 Go 版本中關於規範可比較類型與可比較類型的不一致問題。
以上是Go 泛型對映射鍵的「可比較」約束可以放寬嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!