为何Go的slices包BinarySearch函数采用带S类型参数的定义?
为什么Go slices包的BinarySearch用
[S ~[]E, E cmp.Ordered]而非[E cmp.Ordered] 核心区别:兼容自定义切片类型
第一种定义里的S ~[]E是Go泛型的底层类型约束,意思是S可以是任何底层类型为[]E的类型——既包括原生的[]E切片,也包括用type XXX []E定义的自定义切片类型。而第二种定义的参数x []E只能接受原生切片,完全不兼容自定义切片类型。
能跑通第一种但第二种编译失败的代码示例
比如我们定义一个自定义的int切片类型,看看两种定义的差异:
package main import ( "cmp" "slices" ) // 自定义切片类型,底层是[]int type MyIntSlice []int func main() { mySlice := MyIntSlice{1, 3, 5, 7, 9} target := 5 // 调用标准库的BinarySearch(第一种定义),正常编译运行 idx, found := slices.BinarySearch(mySlice, target) println("标准库版本:索引", idx, "找到?", found) // 自己实现第二种定义的BinarySearch myBinarySearch := func[E cmp.Ordered](x []E, target E) (int, bool) { return slices.BinarySearch(x, target) } // 解开下面这行注释会直接编译报错: // cannot use mySlice (variable of type MyIntSlice) as type []int in argument to myBinarySearch // idx2, found2 := myBinarySearch(mySlice, target) // println("自定义版本:索引", idx2, "找到?", found2) }
注释掉的代码之所以报错,是因为MyIntSlice是独立的自定义类型,和原生[]int不是同一类型,无法匹配第二种定义里的x []E参数;但标准库的版本因为用了~[]E的约束,能识别出MyIntSlice的底层类型是[]int,所以可以正常调用。
这么设计的意义
Go里自定义类型和它的底层类型是两个不同的类型,但很多场景下我们希望自定义切片能直接复用标准库的切片工具函数。用~[]E的约束可以让API支持所有“本质是切片”的类型,不用为每个自定义切片重复造轮子,大幅提升了标准库工具函数的灵活性和复用性。
内容的提问来源于stack exchange,提问作者Bomgar
相关产品推荐
相关产品推荐

