Go语言中的`sort`包会影响到所有的切片。

huangapple go评论109阅读模式
英文:

Package sort in go affects all slices

问题

我在Go语言中创建了一个字符串切片。然后,我创建了另外两个切片。第一个是unsorted原始切片,第二个是sorted原始切片。但是,当我使用sort包对第二个切片进行排序时,第一个切片也被排序了。我应该如何只对第二个切片进行排序呢?

og := []string{"go", "python", "java", "C++"}
unsorted := append([]string(nil), og...)
sorted := append([]string(nil), og...)

sort.Strings(sorted)

fmt.Println("unsorted", unsorted)
fmt.Println("sorted", sorted)

实际输出:

unsorted [C++ go java python]
sorted [C++ go java python]

期望输出:

unsorted [go python java C++]
sorted [C++ go java python]
英文:

I make a slice of strings in go. Then, I make two other slices. The first is the unsorted original slice, and the second is the sorted original slice. But, when I sort the second slice using package sort, the first slice is getting sorted as well. How can I sort only the second one?

    og := []string{"go", "python", "java", "C++"}
    unsorted :=og
    sorted := og
    
    sort.Strings(sorted)
    
    fmt.Println("unsorted", unsorted)
    fmt.Println("sorted", sorted)

Actual output:

    unsorted [C++ go java python]
    sorted [C++ go java python]

Expected output:

    unsorted [go python java C++]
    sorted [C++ go java python]

答案1

得分: 2

切片有时被称为“引用类型”。你可以在这里阅读更多有关数组和切片之间的区别的信息(我找到的第一页)。

runtime包的源代码中(slice.go文件)可以看出切片的基本结构:

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

当你将切片分配给unsortedsorted变量时,你实际上是创建了一个对这个底层slice结构的副本。你实际上是复制了指向底层数组的指针,而这个指针是由sort.Strings()操作的,因此对切片的两个引用都会反映这些更改。

为了避免看到顺序的改变,你需要将切片复制到一个新的切片中,可以在这里找到一个Go Playground的示例代码。

为了完整起见:

og := []string{"go", "python", "java", "C++"}
unsorted := make([]string, len(og)) // 创建一个新的切片
copy(unsorted, og) // 复制值
sorted := og // 这行不是必需的,你可以直接对og进行排序
sort.Strings(sorted)
fmt.Printf("%#v\n%#v\n", unsorted, sorted)

除了使用make和调用copy之外,你还可以简化代码,如下所示:

unsorted := append([]string{}, og...) // 追加到新的切片中,相当于复制
英文:

So slices are sometimes referred to as reference types. You can read more about the differences between arrays and slices here, for example (first page I found).

What a slice basically is, as you can see from the source in the runtime package (slice.go file):

type slice struct {
    array unsafe.Pointer
	len   int
	cap   int
}

When you're assigning the slice to unsorted and the sorted variables, you're creating a copy of this underlying slice struct. You're essentially copying the pointer to the underlying array, which is being manipulated by sort.Strings(), hence both references to the slice will reflect these changes.

What you'll want to do is copy the slice into a new one to avoid seeing the order change a go playground snippet here.

For completeness sake:

og := []string{"go", "python", "java", "C++"}
unsorted := make([]string, len(og)) // create a new slice
copy(unsorted, og) // copy over values
sorted := og // this isn't a required line, you can just sort og
sort.Strings(sorted)
fmt.Printf("%#v\n%#v\n", unsorted, sorted)

Rather than using make and calling copy, you can simplify it as follows:

unsorted := append([]string{}, og...) // append to new slice == copy

答案2

得分: 1

当你将一个切片分配给另一个切片时,你会得到一个浅拷贝。它们都将引用相同的底层数组数据。

如果你想修改其中一个切片并保留原始数据,你需要复制切片的内容,然后进行修改。

package main

import (
	"fmt"
	"sort"
)

func copySlice(slice []string) []string {
	newSlice := make([]string, len(slice))
	copy(newSlice, slice)
	return newSlice
}

func main() {
	og := []string{"go", "python", "java", "C++"}
	unsorted := copySlice(og)
	sorted := copySlice(og)

	sort.Strings(sorted)

	fmt.Println("unsorted", unsorted)
	fmt.Println("sorted", sorted)
}
英文:

When you assign one slice to a another you get a shallow copy.
They will both refer to the same underlying array of data.

If you want to modify one and keep the original, you would need to copy the content of the slice, then modify it.

package main

import (
	"fmt"
	"sort"
)

func copySlice(slice []string) []string {
	newSlice := make([]string, len(slice))
	copy(newSlice, slice)
	return newSlice
}

func main() {
	og := []string{"go", "python", "java", "C++"}
	unsorted := copySlice(og)
	sorted := copySlice(og)

	sort.Strings(sorted)

	fmt.Println("unsorted", unsorted)
	fmt.Println("sorted", sorted)
}

huangapple
  • 本文由 发表于 2021年10月19日 19:19:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/69629835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定