英文:
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
}
当你将切片分配给unsorted
和sorted
变量时,你实际上是创建了一个对这个底层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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论