2 回答
TA貢獻1853條經(jīng)驗 獲得超6個贊
為什么泛型類型開關(guān)編譯失???
這其實是 Go 團隊有意決定的結(jié)果。事實證明,允許參數(shù)化類型上的類型切換會導(dǎo)致混淆
在此設(shè)計的早期版本中,我們允許在類型為類型參數(shù)或類型基于類型參數(shù)的變量上使用類型斷言和類型開關(guān)。我們刪除了此功能,因為始終可以將任何類型的值轉(zhuǎn)換為空接口類型,然后對其使用類型斷言或類型切換。此外,有時令人困惑的是,在使用近似元素的類型集的約束中,類型斷言或類型切換將使用實際類型參數(shù),而不是類型參數(shù)的基礎(chǔ)類型(差異在識別部分中解釋)匹配的預(yù)聲明類型)
讓我把強調(diào)的語句變成代碼。如果類型約束使用類型近似(注意波浪號)...
func PrintStringOrInt[T ~string | ~int](v T)
...如果還有一個自定義類型int作為基礎(chǔ)類型...
type Seconds int
...如果PrintOrString()使用Seconds參數(shù)調(diào)用...
PrintStringOrInt(Seconds(42))
...那么switch塊不會進入,int case而是直接進入default case,因為Seconds不是int。開發(fā)人員可能希望它也case int:與類型相匹配Seconds。
要允許一個case語句同時匹配Seconds和int將需要一個新的語法,例如,
case ~int:
在撰寫本文時,討論仍在進行中,也許會產(chǎn)生一個全新的選項來打開類型參數(shù)(例如switch type T)。
更多細節(jié)請參考提案:spec: generics: type switch on parametric types
技巧:將類型轉(zhuǎn)換為“任何”
幸運的是,我們不需要等待這個提議在未來的版本中得到實施?,F(xiàn)在有一個超級簡單的解決方法。
不是打開v.(type),而是打開any(v).(type)。
switch any(v).(type) {
...這個技巧轉(zhuǎn)換v成一個空的interface{}(又名any),很switch高興地為它進行類型匹配。
TA貢獻1820條經(jīng)驗 獲得超10個贊
*A[any]不匹配*A[int],因為any是靜態(tài)類型,不是通配符。因此,用不同類型實例化一個泛型結(jié)構(gòu)會產(chǎn)生不同的類型。
為了在類型轉(zhuǎn)換中正確匹配泛型結(jié)構(gòu),您必須使用類型參數(shù)實例化它:
func Handle[T any](s interface{}) {
switch x := s.(type) {
case *A[T]:
x.DoA()
case *B[T]:
x.DoB()
default:
panic("no match")
}
}
盡管在沒有其他函數(shù)參數(shù)的情況下 infer T,您將不得不調(diào)用Handle顯式實例化。T不會僅從結(jié)構(gòu)中推斷出來。
func main() {
i := &A[int]{}
Handle[int](i) // expected to print "do A"
}
游樂場:https ://go.dev/play/p/2e5E9LSWPmk
但是,當(dāng)Handle實際上是一種方法時,就像在您的數(shù)據(jù)庫代碼中一樣,這具有在實例化接收器時選擇類型參數(shù)的缺點。
為了改進這里的代碼,您可以創(chuàng)建Handle一個頂級函數(shù):
func Handle[T any](ctx context.Context, cmd CMD) error {
switch t := cmd.(type) {
case *TransactionalCommand[T]:
return handleTransactionalCommand(ctx, t)
default:
fmt.Printf("%T\n", cmd)
return ErrInvalidCommand
}
}
那么你就會遇到如何向db T命令函數(shù)提供參數(shù)的問題。為此,您可能會:
只需將一個附加*db參數(shù)傳遞給Handleand handleTransactionalCommand,這也有助于類型參數(shù)推斷。調(diào)用為Handle(ctx, &db{}, tFn)。游樂場:https ://go.dev/play/p/6WESb86KN5D
傳遞一個實例CommandManager(如上面的解決方案但*db被包裝)。更冗長,因為它需要在任何地方顯式實例化。游樂場:https ://go.dev/play/p/SpXczsUM5aW
改用參數(shù)化接口(如下所示)。因此,您甚至不必進行類型切換。游樂場:https ://go.dev/play/p/EgULEIL6AV5
type CMD[T any] interface {
Exec(ctx context.Context, db T) error
}
- 2 回答
- 0 關(guān)注
- 182 瀏覽
添加回答
舉報
