`copy ()`로 슬라이스를 복제 할 수없는 이유는 무엇입니까?


121

Go에서 조각의 복사본을 만들고 문서를 읽어야하며 복사 기능이 있습니다.

copy 내장 함수는 소스 슬라이스의 요소를 대상 슬라이스로 복사합니다. (특별한 경우로, 또한 문자열에서 바이트 조각으로 바이트를 복사합니다.) 소스와 대상이 겹칠 수 있습니다. Copy는 복사 된 요소의 수를 반환하며, 이는 len (src) 및 len (dst)의 최소값입니다.

하지만 내가 할 때 :

arr := []int{1, 2, 3}
tmp := []int{}
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

tmp이전과 같이 비어 있습니다 (사용하려고 시도했습니다 arr, tmp).

[]
[1 2 3]

이동 놀이터 에서 확인할 수 있습니다 . 그렇다면 슬라이스를 복사 할 수없는 이유는 무엇입니까?


모두에게 감사합니다. 슬라이스가 같은 길이 여야한다는 것을 알아 차리지 못한 것이 정말 슬프습니다.
Salvador Dali

1
반드시 동일하지는 않지만 dst최소한 복사하려는 요소만큼 커야합니다 (전체 사본은 src을 의미합니다 len(dst) >= len(src)).
icza

2
b := append([]int{}, a...)
rocketspacer 2017-06-20

답변:


209

내장 copy(dst, src)min(len(dst), len(src))요소를 복사 합니다.

따라서 dst비어 있으면 ( len(dst) == 0) 아무것도 복사되지 않습니다.

tmp := make([]int, len(arr))( Go Playground ) 시도 :

arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

출력 (예상대로) :

[1 2 3]
[1 2 3]

불행히도 이것은 builtin패키지에 문서화되어 있지 않지만 Go Language Specification : Appending to and copying slices에 문서화되어 있습니다 .

복사 된 요소의 수는 len(src)및 의 최소값입니다 len(dst).

편집하다:

마지막으로의 문서 copy()가 업데이트되었으며 이제 소스 및 대상의 최소 길이가 복사된다는 사실이 포함됩니다.

Copy는 복사 된 요소의 수를 반환하며, 이는 len (src) 및 len (dst) 의 최소값 입니다.


2
요약하자면, copy대상 조각이 너무 작은 경우 대상 조각을 늘리는 논리를 포함하지 않지만 다른 내장 함수가 있습니다. append 이 예제에서는 먼저 올바른 크기의 조각을 할당하는 것이 좋습니다. append이미 슬라이스가 있고 끝에 요소를 추가하여 늘리고 싶을 때 사용할 수 있습니다.
thomasrutter

1
그러나 제한되지 않은 크기의 슬라이스를 복사 할 때 제한된 크기의 슬라이스를 만들어야합니까?
Alex

24

이를 수행하는 또 다른 간단한 방법 append은 프로세스에서 슬라이스를 할당하는 방법을 사용 하는 것입니다.

arr := []int{1, 2, 3}
tmp := append([]int(nil), arr...)  // Notice the ... splat
fmt.Println(tmp)
fmt.Println(arr)

출력 (예상대로) :

[1 2 3]
[1 2 3]

따라서 배열 복사의 약칭 arr은 다음과 같습니다.append([]int(nil), arr...)

https://play.golang.org/p/sr_4ofs5GW


8
여기서 중요한 점은 훨씬 더 큰 실제 예제에서 append가 추가 메모리를 할당한다는 것입니다. play.golang.org/p/5_6618xnXn 은 cap (x)가 10이 아닌 12로 증가하는 것을 관찰합니다. 이제 1048576 개의 값에 1 개의 값이 추가되면 어떻게되는지보세요. play.golang.org/p/nz32JPehhl 용량이 2048 슬롯만큼 1050624, 하나의 추가 값만 수용합니다.
j. 앤드류는 shusta

12

슬라이스 크기 가 같으면 작동합니다 .

arr := []int{1, 2, 3}
tmp := []int{0, 0, 0}
i := copy(tmp, arr)
fmt.Println(i)
fmt.Println(tmp)
fmt.Println(arr)

줄 것 :

3
[1 2 3]
[1 2 3]

" Go Slices : 사용법 및 내부 "에서 :

복사 기능은 길이가 다른 슬라이스 사이의 복사를 지원합니다 ( 소수의 요소까지만 복사합니다 ).

일반적인 예는 다음과 같습니다.

t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t

10

copy ()는 dst와 src의 최소 길이로 실행되므로 dst를 원하는 길이로 초기화해야합니다.

A := []int{1, 2, 3}
B := make([]int, 3)
copy(B, A)
C := make([]int, 2)
copy(C, A)
fmt.Println(A, B, C)

산출:

[1 2 3] [1 2 3] [1 2]

append ()를 사용하여 nil 슬라이스에 모든 요소를 ​​한 줄에 초기화하고 복사 할 수 있습니다.

x := append([]T{}, []...)

예:

A := []int{1, 2, 3}
B := append([]int{}, A...)
C := append([]int{}, A[:2]...)
fmt.Println(A, B, C)    

산출:

[1 2 3] [1 2 3] [1 2]

할당 + 복사 ()와 비교하여 1,000 개 이상의 요소에 대해서는 append를 사용하십시오. 실제로 1,000 개 미만의 차이는 무시할 수 있습니다. 슬라이스가 많지 않은 경우 경험적으로 확인하십시오.

BenchmarkCopy1-4                50000000            27.0 ns/op
BenchmarkCopy10-4               30000000            53.3 ns/op
BenchmarkCopy100-4              10000000           229 ns/op
BenchmarkCopy1000-4              1000000          1942 ns/op
BenchmarkCopy10000-4              100000         18009 ns/op
BenchmarkCopy100000-4              10000        220113 ns/op
BenchmarkCopy1000000-4              1000       2028157 ns/op
BenchmarkCopy10000000-4              100      15323924 ns/op
BenchmarkCopy100000000-4               1    1200488116 ns/op
BenchmarkAppend1-4              50000000            34.2 ns/op
BenchmarkAppend10-4             20000000            60.0 ns/op
BenchmarkAppend100-4             5000000           240 ns/op
BenchmarkAppend1000-4            1000000          1832 ns/op
BenchmarkAppend10000-4            100000         13378 ns/op
BenchmarkAppend100000-4            10000        142397 ns/op
BenchmarkAppend1000000-4            2000       1053891 ns/op
BenchmarkAppend10000000-4            200       9500541 ns/op
BenchmarkAppend100000000-4            20     176361861 ns/op

1
append는 반복적 인 호출로 인해 어레이가 증가하는 경우에 사용해야합니다.이를 예상하여 초과 용량을 낙관적으로 할당하기 때문입니다. 복사는 결과 배열이 정확한 크기로 생성되어야하고 다시 재 할당되지 않는 경우 입력 배열 당 한 번씩 사용해야합니다. play.golang.org/p/0kviwKmGzx 그 결과를 생성 한 벤치 마크 코드를 공유하지 않았기 때문에 유효성을 확인하거나 거부 할 수는 없지만 더 중요한 측면을 간과합니다.
j. 앤드류는 shusta

1
당신은 array가 아닌 'slice'를 의미 합니다. 그들은 다른 것들입니다.
Inanc Gumus

2

Go 프로그래밍 언어 사양

슬라이스에 추가 및 복사

copy 함수는 소스 src에서 대상 dst로 슬라이스 요소를 복사하고 복사 된 요소 수를 반환합니다. 두 인수 모두 동일한 요소 유형 T를 가져야하며 [] T 유형의 슬라이스에 할당 할 수 있어야합니다. 복사 된 요소의 수는 최소 len (src) 및 len (dst)입니다. 특별한 경우로 copy는 또한 문자열 유형의 소스 인수와 함께 유형 [] byte에 할당 가능한 대상 인수를 허용합니다. 이 형식은 문자열의 바이트를 바이트 슬라이스로 복사합니다.

copy(dst, src []T) int
copy(dst []byte, src string) int

tmp에 충분한 공간이 필요합니다 arr. 예를 들면

package main

import "fmt"

func main() {
    arr := []int{1, 2, 3}
    tmp := make([]int, len(arr))
    copy(tmp, arr)
    fmt.Println(tmp)
    fmt.Println(arr)
}

산출:

[1 2 3]
[1 2 3]

0

다음은 슬라이스를 복사하는 방법입니다. 나는 조금 늦었지만 @Dave보다 더 간단하고 빠른 대답이 있습니다. 이것은 @ Dave 's와 같은 코드에서 생성 된 명령어입니다. 이것들 은 내 것이 생성 한 지시입니다. 보시다시피 지침이 훨씬 적습니다. 하는 것은 append(slice)슬라이스를 복사하는 것입니다. 이 코드 :

package main

import "fmt"

func main() {
    var foo = []int{1, 2, 3, 4, 5}
    fmt.Println("foo:", foo)
    var bar = append(foo)
    fmt.Println("bar:", bar)
    bar = append(bar, 6)
    fmt.Println("foo after:", foo)
    fmt.Println("bar after:", bar)
}

다음을 출력합니다.

foo: [1 2 3 4 5]
bar: [1 2 3 4 5]
foo after: [1 2 3 4 5]
bar after: [1 2 3 4 5 6]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.