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

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

通用切片參數和限制為切片類型的參數有什么區別?

通用切片參數和限制為切片類型的參數有什么區別?

Go
慕虎7371278 2022-11-08 15:11:46
考慮實驗包slices。這個包是實驗性的,所以我知道簽名可能會改變;我用它來說明問題??紤]這個包中兩個函數的簽名,slices.Contains并且slices.Grow:func Contains[E comparable](s []E, v E) boolfunc Grow[S ~[]E, E any](s S, n int) S的第一個參數Contains具有類型[]E(Es 的切片)和E受約束的comparable類型(可比較的類型)。Grow相反,第一個參數的類型為S(just S),受(基礎類型為 的切片的類型)S約束~[]EE但是,在具有此類參數的函數內部允許的操作之間似乎沒有任何實際區別。如果我們聲明一些具有相同類型參數的假函數,我們可以看到兩者都編譯得很好:正如預期的那樣,在這兩個函數中,我們可以len/ cap、append、range、 分配make和 索引[ ]。func fakeContains[E comparable](s []E, v E) {    fmt.Println(len(s), cap(s))    var e E    fmt.Println(append(s, e))    fmt.Println(make([]E, 4))    for _, x := range s {        fmt.Println(x)    }    fmt.Println(s[0])        fmt.Println(reflect.TypeOf(s).Kind())}func fakeGrow[S ~[]E, E any](s S, n int) {    fmt.Println(len(s), cap(s))    var e E    fmt.Println(append(s, e))    fmt.Println(make(S, 4))    for _, x := range s {        fmt.Println(x)    }        fmt.Println(s[0])        fmt.Println(reflect.TypeOf(s).Kind())}甚至在所有情況下都reflect.TypeOf(s).Kind()給予。reflect.Slice這些函數也可以用不同的類型進行測試,并且都可以編譯:// compiles just finefunc main() {    type MyUint64 uint64    type MyUint64Slice []uint64    foo := []uint64{0, 1, 2}    fakeContains(foo, 0)    fakeGrow(foo, 5)    bar := []MyUint64{3, 4, 5}    fakeContains(bar, 0)    fakeGrow(bar, 5)    baz := MyUint64Slice{6, 7, 8}    fakeContains(baz, 0)    fakeGrow(baz, 5)}在我的理解中,唯一的實際區別是在slices.Grow參數s S 中不是 slice。它只限于切片類型。事實上reflect.TypeOf(s),當 arg 是 的實例時會給出不同的輸出type MyUint64Slice []uint64:Contains帶 args []E給出reflect.TypeOf(s) -> []uint64Grow帶 args S給出reflect.TypeOf(s) -> main.MyUint64Slice但是,對我來說,兩者之間的實際區別并不是很明顯。帶有代碼的游樂場:https ://gotipplay.golang.org/p/zg2dGtSJwuI問題這兩個聲明在實踐中是否等效?如果沒有,我應該什么時候選擇一個而不是另一個?
查看完整描述

1 回答

?
犯罪嫌疑人X

TA貢獻2080條經驗 獲得超4個贊

如果您必須返回與參數相同(可能命名)類型的切片,這很重要。


如果您不必返回切片(僅返回一些其他信息,例如 abool以報告是否包含該值),則無需使用本身約束切片的類型參數,您可以為元素使用類型參數只要。


如果必須返回與輸入相同類型的切片,則必須使用本身約束到切片的類型參數(例如~[]E)。


為了演示,讓我們看看這兩個實現Grow():


func Grow[S ~[]E, E any](s S, n int) S {

    return append(s, make(S, n)...)[:len(s)]

}


func Grow2[E any](s []E, n int) []E {

    return append(s, make([]E, n)...)[:len(s)]

}

如果您傳遞具有切片作為其基礎類型的自定義類型的切片,Grow()則可以返回相同類型的值。Grow2()不能:它只能返回一個未命名的切片類型的值:[]E。


和演示:


x := []int{1}


x2 := Grow(x, 10)

fmt.Printf("x2 %T len=%d cap=%d\n", x2, len(x2), cap(x2))


x3 := Grow2(x, 10)

fmt.Printf("x3 %T len=%d cap=%d\n", x3, len(x3), cap(x3))


type ints []int

y := ints{1}


y2 := Grow(y, 10)

fmt.Printf("y2 %T len=%d cap=%d\n", y2, len(y2), cap(y2))


y3 := Grow2(y, 10)

fmt.Printf("y3 %T len=%d cap=%d\n", y3, len(y3), cap(y3))

輸出(在Go Playground上試試):


x2 []int len=1 cap=12

x3 []int len=1 cap=12

y2 main.ints len=1 cap=12

y3 []int len=1 cap=12

如您所見Grow2(y, 10),接收一個 type 的值main.ints,但它返回一個 type 的值[]int。這不是我們想要的。


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

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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