我正在学习GO,我有理论上的问题。
如何使用切片副本而不是对它的引用?
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2, 5)
// create slice3 by appending int 4 to slice2
slice3 := append(slice2, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [1 2 4]; how to make sure slice3 is using a copy [0 0 4]?
fmt.Println(slice1, slice2, slice3)
}
我想出了一个潜在的解决方案,但它没有意义,因为它依赖于slice3被创建为空,slice2被copy()
复制到slice3上。没有捷径吗?
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2, 5)
// create slice3, copy slice2 and append int 4 to slice3
slice3 := make([]int, 2)
copy(slice3, slice2)
slice3 = append(slice3, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [0 0 4];
fmt.Println(slice1, slice2, slice3)
}
修改
我read有一种奇特的行为,在这个天真的例子中可以作为解决方案(见下文)。但是,在任何其他情况下,它都行不通。 基本上,如果创建的空切片没有指定基础数组的大小,GO的append函数会提供该数组的副本,否则,如果有增长空间,append将返回引用原始数组的切片。
注意:唯一的变化是slice2 := make([]int, 2, 5)
到slice2 := make([]int, 2)
package main
import "fmt"
func main() {
// slice containing 3 items
slice1 := []int{1, 2, 3}
// make an empty slice
slice2 := make([]int, 2)
// create slice3 by appending int 4 to slice2
slice3 := append(slice2, 4)
// print [0 0 4]
fmt.Println(slice3)
// copy elements of slice1 onto slice2
copy(slice2, slice1)
// print [1 2 3] [1 2] [1 2 4]; how to make sure slice3 is using a copy [0 0 4]?
fmt.Println(slice1, slice2, slice3)
}
playground with a wanted behaviour
所以问题就变成了:当我们追加的切片指向具有指定大小和空间的数组时,是否有可能复制上述行为?
编辑2: 我认为对于我想要达到的目标存在一些困惑。 如何在第一次调用中使用的格式传递切片时获得第二个调用的结果?
package main
import "fmt"
func main() {
fmt.Println("s3 references an array of s1")
worker(make([]int, 2, 5))
fmt.Println("\ns3 copies an array of s1")
worker(make([]int, 2))
}
func worker(s1 []int) {
s2 := []int{1, 2, 3}
fmt.Println(s1)
s3 := append(s1, 4)
fmt.Println(s3)
copy(s1, s2)
fmt.Println(s3)
}
答案 0 :(得分:0)
有些人评论说我昨晚不够清楚。所以我想在@CoreyOgburn和@JimB的帮助下澄清并提供答案
我正在学习关于GO的切片,我发现了一个不一致的地方,这让我相信我做错了什么。虽然这不是一个真实的例子,但我发现以下是复制和追加功能的一个很好的例子。
package main
import "fmt"
func main() {
fmt.Println("s3 references an array of s1")
// we pass a slice of length 2 and capacity 5
worker(make([]int, 2, 5))
fmt.Println("\ns3 copies an array of s1")
// we pass a slice of lenght 2 and capacity 2
worker(make([]int, 2))
}
func worker(s1 []int) {
// create new slice for future use
s2 := []int{1, 2, 3}
fmt.Println(s1)
// create a new slice by appending a value to a slice passed into this function
s3 := append(s1, 4)
// s3 holds whatever was passed into this function + int 4, that we just appended
fmt.Println(s3)
// copy contents of s2 onto s1
copy(s1, s2)
// if s1 had spare capacity when it was passed i.e. make([]int, 2, 5) s3 will be referencing the same array as s1, hence s3 will now hold the same values as s1
// if s1 capacity was the same as its length i.e. make([]int, 2) s3 will be referencing a new array after append(), hence copy has no effect on the values of s3
fmt.Println(s3)
}
@JimB发布了一条评论,其中包含blog post explaining how slices work的链接,如果您正在学习该语言,这是一个很好的阅读。
A possible "gotcha"
部分中最重要的是对“修复”的解释。对于现实生活场景,可以推断为修复我的示例中的不一致。 (创建传递切片的副本并使用它)
Playground