考慮實驗包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 fine
func 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
問題
這兩個宣告在實踐中是否等效?如果沒有,我應該什么時候選擇一個而不是另一個?
uj5u.com熱心網友回復:
如果您必須回傳與引數相同(可能命名)型別的切片,這很重要。
如果您不必回傳切片(僅回傳一些其他資訊,例如 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。這不是我們想要的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/426099.html
上一篇:使用泛型實作可比較的結構
下一篇:這兩種通用方法有什么區別?
