考虑实验包slices
。这个包是实验性的,所以我知道签名可能会改变;我用它来说明问题。
考虑这个包中两个函数的签名,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
s 的切片)和E
受约束的comparable
类型(可比较的类型)。
Grow
相反,第一个参数的类型为S
(just 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
中不是 slice。它只限于切片类型。事实上reflect.TypeOf(s)
,当 arg 是 的实例时会给出不同的输出type MyUint64Slice []uint64
:
Contains
带 args []E
给出reflect.TypeOf(s) -> []uint64
Grow
带 args S
给出reflect.TypeOf(s) -> main.MyUint64Slice
但是,对我来说,两者之间的实际区别并不是很明显。
带有代码的游乐场:https ://gotipplay.golang.org/p/zg2dGtSJwuI
这两个声明在实践中是否等效?如果没有,我应该什么时候选择一个而不是另一个?
犯罪嫌疑人X
相关分类