preliminary
empty interface,type assertion,type switch
探究这个问题的缘由:使用sort.Slice(slice interface{}, less func(i int, j int) bool)
函数,比如下面的代码示例,我传入sort.Slice
的第一个参数是对象而不是指针,如果算作值传递的话应该会引起对象拷贝,sort.Slice
函数只是在对拷贝做排序,不影响原对象,而实际结果是如图所示即在原对象上进行了排序。
slice := []int{
4, 3, 1, 2, 5}
sort.Slice(slice, func(i, j int) bool {
if slice[i] < slice[j] {
return true
}
return false
})
fmt.Println(slice) // [1 2 3 4 5]
这个问题很明显地就出在了interface{}
这个可以代表任何类型的符号上了(或者说任何类型都实现了interface{}
)。在Go Data Structures: Interfaces中解释了interface的数据结构,即一个指向interface table的指针和一个指向被转换为interface的数据的指针,由于在本例中使用的是interface{}
,所以第一个指针可以被简化为指向类型的指针(对应为src/reflect/type.go:296的rtype
),而文中说第二个指针在数据可以fit进一个word的时会直接拷贝,这个我实测倒没有发生。总而言之,在变量a被转换为empty interface变量b之后,b中保存着指向a的数据的指针,而非拷贝。 于是sort.Slice
函数可以利用指针直接改变原有数组的排列。
再来看一下sort.Slice
的实现
func Slice(slice interface{
}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
quickSort_func(lessSwap{
less, swap}, 0, length, maxDepth(length))
}
reflect.Swapper
函数中其实也使用了reflect.ValueOf
函数