我正在学习围棋,我有一个理论问题。
如何使用切片的副本而不是对其的引用?
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)
}
问题游乐场连接
我提出了一个可能的解决方案,但它毫无意义,因为它依赖于将切片3创建为空,并通过copy()
将切片2复制到切片3上。没有捷径吗?
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)
}
解决方案游乐场链接
编辑:
我已经读到,在这个天真的例子中,有一种特殊的行为可以作为解决方案(见下文)。然而,在任何其他情况下,这都是行不通的。基本上,如果创建空切片时没有指定底层数组的大小,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)
}
操场上有被通缉的行为
因此问题变成了:当我们附加到的切片指向具有指定大小和增长空间的数组时,是否有可能复制上述行为?
编辑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)
}
游戏场
有几个人评论说我昨晚不够清楚。因此,我想澄清并提供一个我在@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发表了一篇评论,链接到一篇博客文章,解释了切片是如何工作的,如果你正在学习这门语言,这是一篇很好的文章。在一节中最重要的是一个可能的“明白”
有一个对现实生活场景的“修复”的解释,可以推断为修复我的例子中的不一致性。(创建一个传递的切片的副本,并使用取而代之的是)
游乐场
我有三个表在我的应用程序,把它们称为,,和。有字段为和,两者都有索引。有字段带索引,有字段带索引。 当我执行以下查询时: 它真的很慢(约1秒)。 当我执行以下查询时: 速度非常快(约20毫秒)。 据我所知,这些桌子大小差不多 关于这两个查询之间的巨大性能差异,有什么想法吗? 表大小: > tableA:2061392行 表B:175339行 TableC: 1888912行 postgresql-
问题内容: 我正在使用PDO 进行SQL查询的注册表单。插入之后,我想提取刚刚创建的(自动递增,主键),并将其放入另一个表(“确认代码”表)中。 但是,如何确定该用户名不是第二位用户的用户名,后者在第一位用户之后的1/1000秒内注册呢? 我应该找到某种方法锁定桌子吗?我应该使用交易吗? 问题答案: 返回 在该连接 上插入的最后一行的标识符,因此并发用户(与数据库具有不同的连接)不会受到干扰。
问题内容: 我有一个简单的代码可以生成随机数 上面的方法被调用大约10次(不是循环的)。我想确保所有数字都是唯一的(假设)。 我可以确定每次呼叫都会得到唯一的号码吗?如果没有,我该如何解决? 编辑:我可能已经含糊其词了。我想避免手动检查,如果我真的有唯一的数字,所以我想知道是否有更好的解决方案。 问题答案: 有多种方法可以实现这一目标,哪种方法更合适,取决于您需要从多少个数字中选择。 如果要从大量
我的问题是如何创建像这样的类? (内置类型)没有属性,即使这个的是。 而且它没有使用
我是JavaScript的新手,我认为对象是通过引用传递的。 我期望的输出是: 获得的输出: 当引用的地址时,为什么仍然 null null
但似乎静态变量背后的过程是不同的!那么,这个静态变量背后到底发生了什么,它是如何工作的呢?