slices.Contains
和
slices.Grow
:
func Contains[E comparable](s []E, v E) bool
func Grow[S ~[]E, E any](s S, n int) S
Contains
的第一个参数具有类型
[]E
(
E
的切片),其中
E
受
comparable
(可比较的类型)约束。
Grow
的第一个参数具有类型
S
(只是
S
),
S
受
~[]E
约束(基础类型是
E
切片的类型)然而,具有此类类型参数的函数内部允许执行的操作似乎没有任何实际差异。如果我们声明一些具有相同类型参数的伪函数,我们可以看到两者都编译得很好:
正如预期的那样,在这两个函数中,我们可以
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
不是切片。它只是“约束”到切片类型。事实上,当 arg 是
reflect.TypeOf(s)
的实例时,type MyUint64Slice []uint64
会给出不同的输出:
Contains
s []E
给出
reflect.TypeOf(s) -> []uint64
Grow
s S
给出
reflect.TypeOf(s) -> main.MyUint64Slice
但是,我并不清楚两者之间的带有代码的游乐场:https://gotipplay.golang.org/p/zg2dGtSJwuI
如果
如果您不必返回切片(只需返回一些其他信息,例如 bool
如果必须返回与输入类型相同的切片,则必须使用本身限制为切片的类型参数(例如
~[]E
)。
为了演示,让我们看看
Grow()
的这 2 个实现:
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)
接收类型为main.ints
的值,但它返回类型为
[]int
的值。这不是我们想要的。禁止我
毁了我
消灭我
我是一个没有价值的人
我没有生活,没有工作,没有朋友,也没有收入