我試圖了解 Go 泛型(v1.18)中型別聯合約束的用法。這是我嘗試過的代碼:
type A struct {
}
type B struct {
}
type AB interface {
*A | *B
}
func (a *A) some() bool {
return true
}
func (b *B) some() bool {
return false
}
func some[T AB](x T) bool {
return x.some() // <- error
}
編譯器抱怨:
x.some未定義(型別T沒有欄位或方法)
這是為什么?如果我不能使用型別*Aand的共享方法*B,那么定義型別聯合的意義*A | *B何在?
(顯然我可以使用共享方法定義一個介面并直接使用它。但在我的特定用例中,我想明確限制某些型別。)
uj5u.com熱心網友回復:
將宣告更改AB為
type AB interface {
*A | *B
some() bool
}
在 Generic Go 中,約束是介面。如果型別引數實作了它的約束,則它是有效的。
請觀看有關泛型的 Gophercon 視頻以更好地理解:
- Gophercon 2021:Robert Griesemer 和 Ian Lance Taylor - 仿制藥!
- Gophercon 2020:Robert Griesemer - 打字 [通用] Go
為確保我理解您的問題,請在Go Playground 中以“Go Dev 分支”模式運行以下代碼片段:
// You can edit this code!
// Click here and start typing.
package main
import "fmt"
type A struct {
}
type B struct {
}
type C struct{}
type AB interface {
*A | *B
some() bool
}
func (a *A) some() bool {
return true
}
func (b *B) some() bool {
return false
}
func (c *C) some() bool {
return false
}
func some[T AB](x T) bool {
return x.some()
}
func main() {
p := new(A)
fmt.Println(some(p))
//uncomment the lines below to see that type C is not valid
//q := new(C)
//fmt.Println(some(q))
}
uj5u.com熱心網友回復:
將方法添加到介面約束,而不放棄泛型:
type AB interface {
*A | *B
some() bool
}
func some[T AB](x T) bool {
return x.some() // works
}
這僅限T于為*Aor*B和宣告some() bool方法的型別。
但是,正如您已經發現的那樣,這是一種解決方法。你是對的,它應該單獨使用型別聯合。這是 Go 1.18 的限制。令人困惑的部分是語言規范似乎仍然支持您的理論(方法集):
介面型別的方法集是介面型別集中每個型別的方法集的交集(生成的方法集通常只是介面中宣告的方法集)。
此限制似乎僅記錄在Go 1.18 發行說明中:
當前的泛型實作有以下限制:
[...] Go 編譯器目前僅支持在型別引數型別的
m值上呼叫方法,前提是由的約束介面顯式宣告。[...] 盡管可能在方法集中,因為所有型別都在implement . 我們希望在 Go 1.19 中取消這個限制。xPmPmPPm
Go 跟蹤器中的相關問題是#51183, Griesemer確認并決定保持語言規范不變,并記錄限制。
uj5u.com熱心網友回復:
我認為舊的 interface{} 足以做到這一點。
像這樣:
type AB interface {
some() bool
}
但是如果要使用泛型,則必須先更改型別。
像這樣:
func some[T AB](x T) bool {
if a, ok := interface{}(x).(*A); ok {
return a.some()
}
return (*B)(x).some()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438837.html
