【问题标题】:Go sorts slice correctly, but doesn't sort arrayGo 对切片进行正确排序,但不对数组进行排序
【发布时间】:2014-01-08 14:29:08
【问题描述】:

我很困惑为什么这段代码不起作用:

package main

import (
    "fmt"
    "sort"
)

type T [2]int

func (t T) Len() int           { return len(t) }
func (t T) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t T) Less(i, j int) bool { return t[i] < t[j] }

func main() {
    var x = [2]int{1, 0}
    fmt.Println(x)
    sort.Sort(T(x))
    fmt.Println(x)
}

它输出(不正确):

[1 0]
[1 0]

将 T 的类型更改为 slices 是正确的。

【问题讨论】:

  • IMO,Swap 不会对接收者做任何事情,即t := T(x) t.Swap(0, 1) 不会造成任何影响。
  • Everything in Go is passed (and assigned) by value,数组也不例外。切片具有所谓的“引用语义”,这意味着它们的值包含对底层数据存储的引用,因此将切片传递给函数复制切片值复制共享 i> 具有原始切片值的底层数据存储*。
  • kostix,您的链接提到“Go 中的所有内容都是按值传递的,但是有三个内置的“引用类型”也按值传递,但在内部它们包含对单独维护的数据的引用结构:地图、切片、通道”。但我在官方Go spec 中找不到任何提及。我错过了什么吗?谢谢。
  • @epsylon,不,我想你没有。我对此的看法是,规范是一种法律文件:它可能过于简洁,但作为交换,它是最小的——它只定义了形式上重要的内容。这里调用了值具有引用语义的类型的概念,以帮助人们理解为什么他们会以他们的行为方式行事;它们很可能在语言中正式不存在,但它们确实存在。
  • @epsylon,您也可以从另一个角度看待这个问题:规范没有解释“为什么”,也没有描述它定义的概念与其他规范中的类似概念的行为方式有何不同。比如说,如果映射的分配克隆了这些映射,那么规范应该会明确定义,但由于它们没有,规范对此保持沉默。

标签: go


【解决方案1】:

切片本质上是引用类型,这意味着切片头包含一个指向支持数组的指针,因此它们可以在没有指针接收器的情况下进行变异。数组不是引用类型,在调用您的方法时会被完整复制。

为了对数组执行此操作,您需要更改所有内容以使用指针,因此您的代码可能如下所示:

package main

import (
    "fmt"
    "sort"
)

type T [2]int

func (t *T) Len() int           { return len(t) }
func (t *T) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t *T) Less(i, j int) bool { return t[i] < t[j] }

func main() {
    var x = T([2]int{1, 0})
    fmt.Println(x)
    sort.Sort(&x)
    fmt.Println(x)
}

【讨论】:

    猜你喜欢
    • 2016-02-20
    • 2013-03-20
    • 2016-12-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 2018-02-22
    • 1970-01-01
    • 2020-06-08
    相关资源
    最近更新 更多