简体   繁体   English

如何确保分片正在使用另一个分片的副本而不是对其的引用?

[英]How to make sure slice is using a copy of another slice and not a reference to it?

I'm learning GO and I have a theoretical problem. 我正在学习GO,但有理论上的问题。

How do I use a copy of slice rather than a reference to it? 如何使用切片的副本而不是对其的引用?

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)
}

problem playground link 问题游乐场链接

I have came up with a potential solution, but it is pointless as it relies on slice3 being created empty and slice2 being copied via copy() onto slice3. 我想出了一个潜在的解决方案,但它毫无意义,因为它依赖于slice3被创建为空并且slice2通过copy()到slice3上。 Is there no shortcut? 有没有捷径?

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)
}

solution playground link 解决方案链接

EDIT: 编辑:

I've read that there is a peculiar behaviour that in this naive example would work as a solution (see below). 我已经读到 ,在这个幼稚的示例中有一种特殊的行为可以作为解决方案(见下文)。 However, in any other case it would not work. 但是,在任何其他情况下,它都不起作用。 Basically, if the empty slice is created without the size of an underlying array being specified, GO's append function provides a copy of that array, otherwise, if there is room to grow, append will return a slice that references the original array. 基本上,如果创建空切片时未指定基础数组的大小,则GO的append函数将提供该数组的副本,否则,如果有增长空间,则append将返回引用原始数组的切片。

Note: the only change is slice2 := make([]int, 2, 5) into slice2 := make([]int, 2) 注意:唯一的变化是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 有通缉行为的游乐场

So the question becomes: Is it possible to replicate the behaviour of the above, when the slice we are appending to points to an array with specified size and room to grow? 因此问题就变成了:当我们要附加的切片指向具有指定大小和增长空间的数组时,是否可以复制上述行为?

EDIT 2: I think there is some confusion as to what I want to achieve. 编辑2:我认为我要实现的目标有些混乱。 How to get the result of the second call while passing a slice in the format used in the first call? 在以第一次调用中使用的格式传递切片时,如何获取第二次调用的结果?

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)
}

playground 操场

A few people commented that I was not clear enough last night. 一些人评论说我昨晚不够清楚。 So I would like to clarify and provide an answer that I arrived at with the help of @CoreyOgburn and @JimB 因此,我想澄清一下,并提供一个在@CoreyOgburn和@JimB的帮助下得出的答案。

I was learning about slices in GO and I found an inconsistency, that led me to believe I'm doing something wrong. 我在学习GO中的切片时发现不一致,这让我相信自己做错了。 While hardly a real life example I found the following a good example of the copy and append functionality. 虽然这不是一个真实的例子,但我发现以下是复制和追加功能的一个很好的例子。

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 posted a comment with a link to a blog post explaining how slices work , which is a great read if you are learning the language. @JimB发表了评论,并提供了指向博客文章的链接,该文章解释了切片的工作原理 ,如果您正在学习该语言,那么这是一本好书。 What is most important in the section A possible "gotcha" there is an explanation of a 'fix' to a real life scenario, that can be extrapolated as a fix the inconsistency in my example. A possible "gotcha"部分中,最重要的是对真实场景的“修复”进行了解释,可以将其推断为修复示例中的不一致之处。 (create a copy of a passed slice and use that instead) (创建传递的切片的副本,并使用该副本)
Playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM