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

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

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

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

剛開(kāi)始學(xué)習(xí)泛型。我正在制作一個(gè)命令處理器,老實(shí)說(shuō)我不知道如何表達(dá)這個(gè)所以我只是想展示一個(gè)示例問(wèn)題: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)    }}為什么這個(gè) switch 語(yǔ)句大小寫不*A[any]匹配*A[int]?如何CommandManager.Handle(...)接受通用命令?
查看完整描述

2 回答

?
墨色風(fēng)雨

TA貢獻(xiàn)1853條經(jīng)驗(yàn) 獲得超6個(gè)贊

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

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

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

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

讓我把強(qiáng)調(diào)的語(yǔ)句變成代碼。如果類型約束使用類型近似(注意波浪號(hào))...

func PrintStringOrInt[T ~string | ~int](v T)

...如果還有一個(gè)自定義類型int作為基礎(chǔ)類型...

type Seconds int

...如果PrintOrString()使用Seconds參數(shù)調(diào)用...

PrintStringOrInt(Seconds(42))

...那么switch塊不會(huì)進(jìn)入,int case而是直接進(jìn)入default case,因?yàn)?code>Seconds不是int。開(kāi)發(fā)人員可能希望它也case int:與類型相匹配Seconds

要允許一個(gè)case語(yǔ)句同時(shí)匹配Secondsint將需要一個(gè)新的語(yǔ)法,例如,

case ~int:

在撰寫本文時(shí),討論仍在進(jìn)行中,也許會(huì)產(chǎn)生一個(gè)全新的選項(xiàng)來(lái)打開(kāi)類型參數(shù)(例如switch type T)。

更多細(xì)節(jié)請(qǐng)參考提案:spec: generics: type switch on parametric types


技巧:將類型轉(zhuǎn)換為“任何”

幸運(yùn)的是,我們不需要等待這個(gè)提議在未來(lái)的版本中得到實(shí)施?,F(xiàn)在有一個(gè)超級(jí)簡(jiǎn)單的解決方法。

不是打開(kāi)v.(type),而是打開(kāi)any(v).(type)。

switch any(v).(type) {
    ...

這個(gè)技巧轉(zhuǎn)換v成一個(gè)空的interface{}(又名any),很switch高興地為它進(jìn)行類型匹配。


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

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超10個(gè)贊

*A[any]不匹配*A[int],因?yàn)閍ny是靜態(tài)類型,不是通配符。因此,用不同類型實(shí)例化一個(gè)泛型結(jié)構(gòu)會(huì)產(chǎn)生不同的類型。


為了在類型轉(zhuǎn)換中正確匹配泛型結(jié)構(gòu),您必須使用類型參數(shù)實(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")

    }

}

盡管在沒(méi)有其他函數(shù)參數(shù)的情況下 infer T,您將不得不調(diào)用Handle顯式實(shí)例化。T不會(huì)僅從結(jié)構(gòu)中推斷出來(lái)。


func main() {

    i := &A[int]{}

    Handle[int](i) // expected to print "do A"

}

游樂(lè)場(chǎng):https ://go.dev/play/p/2e5E9LSWPmk


但是,當(dāng)Handle實(shí)際上是一種方法時(shí),就像在您的數(shù)據(jù)庫(kù)代碼中一樣,這具有在實(shí)例化接收器時(shí)選擇類型參數(shù)的缺點(diǎn)。


為了改進(jìn)這里的代碼,您可以創(chuàng)建Handle一個(gè)頂級(jí)函數(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

    }

}

那么你就會(huì)遇到如何向db T命令函數(shù)提供參數(shù)的問(wèn)題。為此,您可能會(huì):


只需將一個(gè)附加*db參數(shù)傳遞給Handleand handleTransactionalCommand,這也有助于類型參數(shù)推斷。調(diào)用為Handle(ctx, &db{}, tFn)。游樂(lè)場(chǎng):https ://go.dev/play/p/6WESb86KN5D


傳遞一個(gè)實(shí)例CommandManager(如上面的解決方案但*db被包裝)。更冗長(zhǎng),因?yàn)樗枰谌魏蔚胤斤@式實(shí)例化。游樂(lè)場(chǎng):https ://go.dev/play/p/SpXczsUM5aW


改用參數(shù)化接口(如下所示)。因此,您甚至不必進(jìn)行類型切換。游樂(lè)場(chǎng):https ://go.dev/play/p/EgULEIL6AV5


type CMD[T any] interface {

    Exec(ctx context.Context, db T) error

}


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

添加回答

舉報(bào)

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號(hào)

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