为golang类型实现sort.Interface时,为什么方法接收器不需要是指针?

时间:2014-04-02 18:13:20

标签: go

我正在阅读sort stdlib包的文档,示例代码如下所示:

type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }

正如我所知,改变类型T的函数需要使用*T作为其方法接收器。 对于LenSwapLess,为什么会有效?或者我误解了使用T*T作为方法接收者之间的区别?

2 个答案:

答案 0 :(得分:2)

Go有三种参考类型:

  • 地图
  • 信道

这些类型的每个实例都在内部保存一个指向实际数据的指针。这意味着 当你传递其中一种类型的值时,该值是复制,就像其他所有值一样 内部指针仍然指向相同的值。

快速示例(run on play):

func dumpFirst(s []int) {
    fmt.Printf("address of slice var: %p, address of element: %p\n", &s, &s[0])
}

s1 := []int{1, 2, 3}
s2 := s1

dumpFirst(s1)
dumpFirst(s2)

将打印如下内容:

address of slice var: 0x1052e110, address of element: 0x1052e100
address of slice var: 0x1052e120, address of element: 0x1052e100

您可以看到:切片变量的地址发生了变化,但该切片中第一个元素的地址保持不变。

答案 1 :(得分:0)

我对这个完全相同的问题只是一个小小的顿悟。

正如已经解释过的那样,一个类型化的切片(不是指向切片的指针)可以实现sort.Interface接口;部分原因是,即使正在复制切片,其中一个字段也是指向数组的指针,因此对该支持数组的任何修改都将反映在原始切片中。

但是,通常情况下,这不足以证明裸片是可接受的接收器。尝试将结构修改为方法的接收者通常是不正确的,因为任何append()调用都将更改切片副本的长度而不修改原始结构切片的标题。切片修改甚至可能触发新后备阵列的初始化,完全断开复制的接收器与原始切片的连接。

然而,就排序的本质而言,这不是sort.Sort案例中的问题。它运行的唯一数组修改操作是Swap,这意味着数组所需的内存将保持不变,因此切片不会改变大小,因此切片不会有任何变化。 s实际值(起始索引,长度和数组指针)。

我确信这对很多人来说都是显而易见的,但它只是在我身上恍然大悟,而且我认为对于其他人来说这可能是有用的,他们想知道为什么sort可以很好地使用裸片。