I make a slice of strings in go. Then, I make two other slices. The first is unsorted
original slice, and the second is 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]
CodePudding user response:
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
CodePudding user response:
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)
}