第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Go 泛型:為什么 switch case *A[any] 不匹配 *A[int]

Go 泛型:為什么 switch case *A[any] 不匹配 *A[int]

Go
30秒到達戰(zhàn)場 2022-12-05 17:23:04
剛開始學(xué)習(xí)泛型。我正在制作一個命令處理器,老實說我不知道如何表達這個所以我只是想展示一個示例問題:var ErrInvalidCommand = errors.New("invalid command")type TransactionalFn[T any] func(ctx context.Context, db T) errorfunc NewTransactionalCommand[T any](fn TransactionalFn[T]) *TransactionalCommand[T] {    return &TransactionalCommand[T]{        fn: fn,    }}type TransactionalCommand[T any] struct {    fn TransactionalFn[T]}func (cmd *TransactionalCommand[T]) StartTransaction() error {    return nil}func (cmd *TransactionalCommand[T]) Commit() error {    return nil}func (cmd *TransactionalCommand[T]) Rollback() error {    return nil}type CMD interface{}type CommandManager struct{}func (m *CommandManager) Handle(ctx context.Context, cmd CMD) error {    switch t := cmd.(type) {    case *TransactionalCommand[any]:        return m.handleTransactionalCommand(ctx, t)    default:        fmt.Printf("%T\n", cmd)        return ErrInvalidCommand    }}func (m *CommandManager) handleTransactionalCommand(ctx context.Context, cmd *TransactionalCommand[any]) error {    if err := cmd.StartTransaction(); err != nil {        return err    }    if err := cmd.fn(ctx, nil); err != nil {        if err := cmd.Rollback(); err != nil {            return err        }    }    if err := cmd.Commit(); err != nil {        return err    }    return nil}// teststype db struct{}func (*db) Do() {    fmt.Println("doing stuff")}func TestCMD(t *testing.T) {    ctx := context.Background()    fn := func(ctx context.Context, db *db) error {        fmt.Println("test cmd")        db.Do()        return nil    }    tFn := bus.NewTransactionalCommand(fn)    mng := &bus.CommandManager{}    err := mng.Handle(ctx, tFn)    if err != nil {        t.Fatal(err)    }}為什么這個 switch 語句大小寫不*A[any]匹配*A[int]?如何CommandManager.Handle(...)接受通用命令?
查看完整描述

2 回答

?
墨色風(fēng)雨

TA貢獻1853條經(jīng)驗 獲得超6個贊

為什么泛型類型開關(guān)編譯失???

  • 這其實是 Go 團隊有意決定的結(jié)果。事實證明,允許參數(shù)化類型上的類型切換會導(dǎo)致混淆

  • 在此設(shè)計的早期版本中,我們允許在類型為類型參數(shù)或類型基于類型參數(shù)的變量上使用類型斷言和類型開關(guān)。我們刪除了此功能,因為始終可以將任何類型的值轉(zhuǎn)換為空接口類型,然后對其使用類型斷言或類型切換。此外,有時令人困惑的是,在使用近似元素的類型集的約束中,類型斷言或類型切換將使用實際類型參數(shù),而不是類型參數(shù)的基礎(chǔ)類型(差異在識別部分中解釋)匹配的預(yù)聲明類型)

    來自類型參數(shù)提案

讓我把強調(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語句同時匹配Secondsint將需要一個新的語法,例如,

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高興地為它進行類型匹配。


查看完整回答
反對 回復(fù) 2022-12-05
?
拉莫斯之舞

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

}


查看完整回答
反對 回復(fù) 2022-12-05
  • 2 回答
  • 0 關(guān)注
  • 182 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號