亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

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

為什么 Go 中的 maps.Keys() 指定映射類型為 M?

為什么 Go 中的 maps.Keys() 指定映射類型為 M?

Go
喵喵時光機 2022-12-05 11:14:16
我實現了一個函數來獲取映射中的鍵(實際上有幾個版本,用于不同的類型),我更新它以在 Go 1.18 中使用泛型。然后我發現實驗庫已擴展以包含該功能,雖然我的實現幾乎相同,但函數聲明有一些我想更好地理解的差異。這是我的原始通用版本(我重命名了變量以匹配標準庫,以更好地突出顯示實際上是不同的):func mapKeys[K comparable, V any](m map[K]V) []K {    r := make([]K, 0, len(m))    for k := range m {        r = append(r, k)    }    return r}這是標準庫版本:func Keys[M ~map[K]V, K comparable, V any](m M) []K {    r := make([]K, 0, len(m))    for k := range m {        r = append(r, k)    }    return r}如您所見,主要區別在于額外的M ~map[K]V類型參數,我將其省略并直接用于map[K]V函數的參數類型。我的函數有效,那么為什么我需要經歷添加第三個參數化類型的額外麻煩呢?當我寫我的問題時,我想我已經找到了答案:能夠在真正映射的類型上調用函數,但沒有直接聲明為映射,比如在這個DataCache類型上:type DataCache map[string]DataObject我的想法是,這可能需要~map符號,并且~只能在類型約束中使用,而不能在實際類型中使用。該理論的唯一問題是:我的版本在此類地圖類型上運行良好。所以我不知道它有什么用。
查看完整描述

1 回答

?
繁花如伊

TA貢獻2012條經驗 獲得超12個贊

它在非常罕見的情況下是相關的,在這種情況下,您需要聲明一個函數類型的變量(而不調用它),并且您使用另一個在其定義中使用未導出類型的包中的命名映射類型實例化該函數。


當您需要接受和返回定義的類型時,在函數簽名中使用命名類型參數最相關,正如您正確猜測的那樣,正如@icza在此處回答的關于x/exp/slices包的問題。

您關于“代字號類型”只能用于接口約束的說法也是正確的。

現在,包中的幾乎所有函數x/exp/maps實際上并不返回命名類型M。唯一真正做到的是maps.Clone帶有簽名:

func Clone[M ~map[K]V, K comparable, V any](m M) M

然而,由于類型統一,在沒有近似約束的情況下聲明簽名仍然適用于定義的類型。從規格:~map[K]V

[...],因為定義D的類型和類型文字L永遠不會等價,統一將 D 的基礎類型與 L 進行比較

和一個代碼示例:

func Keys[K comparable, V any](m map[K]V) []K {

    r := make([]K, 0, len(m))

    for k := range m {

        r = append(r, k)

    }

    return r

}


type Dictionary map[string]int


func main() {

    m := Dictionary{"foo": 1, "bar": 2}

    k := Keys(m)

    fmt.Println(k) // it just works

}

游樂場:https ://go.dev/play/p/hzb2TflybZ9


附加命名類型參數M ~map[K]V相關的情況是當您需要傳遞函數的實例化值時:


func main() {

    // variable of function type!

    fn := Keys[Dictionary]

    

    m := Dictionary{"foo": 1, "bar": 2}

    fmt.Println(fn(m))

}

游樂場:https ://go.dev/play/p/hks_8bnhgsf


如果沒有M ~map[K]V類型參數,就不可能用定義的類型實例化這樣一個函數值。當然你可以實例化你K的V函數


fn := Keys[string, int]

但是當定義的映射類型屬于不同的包并引用未導出的類型時,這是不可行的:


package foo 


type someStruct struct{ val int }


type Dictionary map[string]someStruct

和:


package main


func main() {

    // does not compile

    // fn := Keys[string, foo.someStruct]


    // this does

    fn := maps.Keys[foo.Dictionary]

}


雖然,這似乎是一個相當通俗的用例。


你可以在這里看到最終的游樂場:https ://go.dev/play/p/B-_RBSqVqUD


但是請記住,這x/exp/maps是一個實驗包,因此簽名可能會隨著未來的 Go 版本和/或當這些函數被提升到標準庫中而改變。


查看完整回答
反對 回復 2022-12-05
  • 1 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號