Go에서 두 조각을 연결


477

슬라이스 [1, 2]와 슬라이스를 결합하려고합니다 [3, 4]. Go에서 어떻게 할 수 있습니까?

나는 시도했다 :

append([]int{1,2}, []int{3,4})

그러나 얻었다 :

cannot use []int literal (type []int) as type int in append

그러나 문서에는 이것이 가능하다는 것을 나타내는 것 같습니다.

slice = append(slice, anotherSlice...)

답변:


877

두 번째 조각 다음에 점을 추가하십시오.

//---------------------------vvv
append([]int{1,2}, []int{3,4}...)

이것은 다른 variadic 함수와 같습니다.

func foo(is ...int) {
    for i := 0; i < len(is); i++ {
        fmt.Println(is[i])
    }
}

func main() {
    foo([]int{9,8,7,6,5}...)
}

37
append()variadic 함수를 ...사용하면 슬라이스에서 variadic 함수에 여러 인수를 전달할 수 있습니다.

11
슬라이스가 상당히 클 때 이것이 성능이 좋습니까? 아니면 컴파일러가 실제로 모든 요소를 ​​매개 변수로 전달하지는 않습니까?
Toad

15
@Toad : 실제로 퍼지지는 않습니다. 위의 foo()예에서 is매개 변수는 원래 슬라이스의 사본을 보유합니다. 즉, 동일한 기본 배열, len 및 cap에 대한 경량 참조 사본이 있습니다. 는 IF foo함수 바꾸는 부재 변화는 원래의 알 수있을 것이다. 여기 데모가 있습니다. 따라서 실제 오버 헤드는 새 슬라이스가없는 경우 foo(1, 2, 3, 4, 5)새 슬라이스를 만드는 것입니다 . 예 : 보유 할 새 슬라이스를 만듭니다 is.

2
아 올바르게 이해하면 가변 변수 함수가 실제로 스택의 모든 매개 변수 대신 매개 변수 배열처럼 구현됩니까? 그리고 당신은 슬라이스를 전달하기 때문에 실제로는 하나씩 매핑합니까?
Toad

@Toad : 그렇습니다 .... 기존 슬라이스에서 사용할 때는 단순히 해당 슬라이스를 전달합니다. 개별 인수를 전달하면 새 인수로 수집되어 전달됩니다. 나는 정확한 역학에 대한 직접적인 지식을 가지고 있지는 않지만, 이것 : foo(1, 2, 3, 4, 5)그리고 이것 : func foo(is ...int) {이것에 대한 설탕 제거 : foo([]int{1, 2, 3, 4, 5})그리고 이것 : func foo(is []int) {.

77

슬라이스에 추가 및 복사

variadic 함수 append는 유형 에 0 개 이상의 값 x을 추가합니다 . s이 유형 S은 슬라이스 유형이어야하며 결과 슬라이스도 유형의 형식으로 반환합니다 S. 값은 x타입의 파라미터에 전달 의 요소 타입 과 통과 규칙이 적용되는 각 파라미터. 특별한 경우에 덧붙여 append는 타입 에 두번째 인자가 뒤에 오는 타입에 할당 할 수있는 첫번째 인자를 받아들 입니다. 이 형식은 문자열의 바이트를 추가합니다....TTS[]bytestring...

append(s S, x ...T) S  // T is the element type of S

s0 := []int{0, 0}
s1 := append(s0, 2)        // append a single element     s1 == []int{0, 0, 2}
s2 := append(s1, 3, 5, 7)  // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
s3 := append(s2, s0...)    // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}

... 매개 변수에 인수 전달

f최종 매개 변수 유형이 가변적인 경우 ...T함수 내에서 인수는 유형의 매개 변수와 같습니다 []T. 을 호출 할 때마다 ffinal 매개 변수에 전달 된 인수는 []T연속 요소가 실제 인수 인 새로운 유형 의 조각으로 , 모두 유형에 지정할 수 있어야합니다 T. 따라서 슬라이스 길이는 최종 매개 변수에 바인딩 된 인수의 수이며 각 호출 사이트마다 다를 수 있습니다.

귀하의 질문에 대한 대답은 예입니다 s3 := append(s2, s0...)에서 이동 프로그래밍 언어 사양 . 예를 들어

s := append([]int{1, 2}, []int{3, 4}...)

6
참고 : append (slice1, slice2 ...)의 일반적인 사용은 나에게 매우 위험한 것 같습니다. slice1이 더 큰 배열의 조각이면 해당 배열의 값이 slice2로 덮어 쓰기됩니다. (이것이 일반적인 관심사가 아닌 것 같아
Hugo

7
@Hugo 만약 당신이 당신의 배열의 조각 위에 "손을 대면", 그 조각 "소유자"는 조각의 현재 길이를 벗어난 배열 부분을 보거나 덮어 쓸 수 있다는 것을 알고 있습니다. 이를 원하지 않으면 최대 용량을 지정 하는 전체 슬라이스 식 (형식 a[low : high : max])을 사용할 수 있습니다 . 예를 들어, 슬라이스 의 용량은 용량을 가지 므로 백업 배열이 그 이후에 1,000 개의 요소를 가지더라도 그 이상의 요소를 포함 하도록 슬라이스 할 수 없습니다. a[0:2:4]4
icza

30

다른 답변에 반대하는 것은 없지만 문서 의 간단한 설명 이 예제의 예보다 이해하기 쉽다 것을 알았 습니다.

func 추가

func append(slice []Type, elems ...Type) []Type내장 기능 추가 기능은 슬라이스 끝에 요소를 추가합니다. 용량이 충분하면 대상이 새 요소를 수용하도록 슬라이스됩니다. 그렇지 않은 경우 새로운 기본 배열이 할당됩니다. 추가는 업데이트 된 슬라이스를 반환합니다. 따라서 추가 결과를 종종 슬라이스 자체를 보유하는 변수에 저장해야합니다.

slice = append(slice, elem1, elem2)
slice = append(slice, anotherSlice...)

특별한 경우, 다음과 같이 바이트 슬라이스에 문자열을 추가하는 것이 합법적입니다.

slice = append([]byte("hello "), "world"...)

1
감사합니다! 나에게 귀중한!
Korjavin Ivan 17

23

나는 (을 reslicing 대상을 reslicing에 의해 지적하고 대상 슬라이스 (당신이 추가 슬라이스가) 충분한 용량이있는 경우, 추가] "이 자리에서"일어날 것을 아는 것이 중요하다고 생각 증가 될하기 위해 길이를 추가 가능한 요소를 수용 할 수 있음).

즉, 결과 슬라이스의 길이를 초과하는 추가 요소가있는 더 큰 배열이나 슬라이스를 슬라이스하여 대상을 만든 경우 덮어 쓸 수 있습니다.

시연하려면이 예제를 참조하십시오.

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

출력 ( Go Playground 에서 시도 ) :

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 10
x: [1 2 3 4]
a: [1 2 3 4 0 0 0 0 0 0]

alength를 가진 "backing"배열 을 만들었습니다 10. 그런 다음 xa배열을 슬라이스 하여 대상 슬라이스를 만들고 y슬라이스는 복합 리터럴을 사용하여 []int{3, 4}만듭니다. 우리가 추가 할 때 지금 yx, 결과는 예상입니다 [1 2 3 4],하지만 놀라게 할 수있다하면 보조 배열이 있다는 것입니다 a용량 때문에 또한, 변경 xIS 10충분 추가하는 y그것, 그래서 x같은 사용되는 resliced되는 a보조 배열을하고, 거기에 append()요소를 복사합니다 y.

이것을 피하려면 다음과 같은 형식 의 전체 슬라이스 식 을 사용할 수 있습니다

a[low : high : max]

슬라이스를 구성하고 결과 슬라이스를로 설정하여 용량을 제어합니다 max - low.

수정 된 예를 참조하십시오 (단지 차이점은 x다음과 같습니다. x = a[:2:2]:

a := [10]int{1, 2}
fmt.Printf("a: %v\n", a)

x, y := a[:2:2], []int{3, 4}
fmt.Printf("x: %v, y: %v\n", x, y)
fmt.Printf("cap(x): %v\n", cap(x))

x = append(x, y...)
fmt.Printf("x: %v\n", x)

fmt.Printf("a: %v\n", a)

출력 ( Go Playground 에서 시도 )

a: [1 2 0 0 0 0 0 0 0 0]
x: [1 2], y: [3 4]
cap(x): 2
x: [1 2 3 4]
a: [1 2 0 0 0 0 0 0 0 0]

보시다시피, 같은 x결과를 얻지 만 a용량 x이 "전용" 이기 때문에 배킹 배열 이 변경되지 않았습니다 2(전체 슬라이스 표현식 덕분에 a[:2:2]). 따라서 추가를 수행하기 위해 x와 의 요소를 모두 저장할 수있는 새로운 배킹 배열이 할당 y됩니다 a.


2
내가 직면 한 문제에 매우 도움이됩니다. 감사.
Aidy

9

@icza 답변을 강조하고 중요한 개념이므로 조금 단순화하고 싶습니다. 나는 독자가 슬라이스에 익숙하다고 가정한다 .

c := append(a, b...)

이것은 질문에 대한 올바른 답변입니다. 그러나 나중에 다른 컨텍스트에서 코드에서 슬라이스 'a'와 'c'를 사용해야하는 경우 슬라이스를 연결하는 안전한 방법이 아닙니다.

설명하기 위해 슬라이스가 아닌 기본 배열의 관점에서 표현식을 읽으십시오.

" 'a'배열을 가져 와서 'b'배열의 요소를 추가하십시오. 'a'배열에 'b'의 모든 요소를 ​​포함 할 수있는 충분한 용량이있는 경우 'c'의 기본 배열은 새로운 배열이 아닙니다. 기본적으로 슬라이스 'a'는 기본 배열 'a'의 len (a) 요소를 표시하고 슬라이스 'c'는 배열 'a'의 len (c)를 표시합니다. "

append ()가 반드시 새로운 배열을 만들 필요는 없습니다! 예기치 않은 결과가 발생할 수 있습니다. Go Playground example을 참조하십시오 .

슬라이스에 새 배열이 할당되도록하려면 항상 make () 함수를 사용하십시오. 예를 들어 여기에는 작업에 대한 추악하지만 효율적인 옵션이 거의 없습니다.

la := len(a)
c := make([]int, la, la + len(b))
_ = copy(c, a)
c = append(c, b...)

la := len(a)
c := make([]int, la + len(b))
_ = copy(c, a)
_ = copy(c[la:], b)

이러한 부작용을 지적 해 주셔서 감사합니다. 이 수정 된 시나리오와 놀랍게 대비됩니다. play.golang.org/p/9FKo5idLBj4 초과 용량을 제공 할 때 이러한 직관에 대한 이러한 수수께끼의 부작용에 대해 신중하게 생각해야합니다.
olippuner 2014

5

append () 함수 및 확산 연산자

append표준 golang 라이브러리의 메소드를 사용하여 두 개의 슬라이스를 연결할 수 있습니다 . variadic기능 작동 과 유사 합니다. 그래서 우리는 사용해야합니다...

package main

import (
    "fmt"
)

func main() {
    x := []int{1, 2, 3}
    y := []int{4, 5, 6}
    z := append([]int{}, append(x, y...)...)
    fmt.Println(z)
}

위 코드의 출력은 다음과 같습니다. [1 2 3 4 5 6]


2

append([]int{1,2}, []int{3,4}...)작동합니다. ...매개 변수에 인수 전달

유형 f이 final 인 variadic 인 경우 p유형 ...Tf에서 type과 p같습니다 []T.

f에 대한 실제 인수없이 호출 된 경우 p전달 된 값 pnil입니다.

그렇지 않으면, 전달 된 값은 []T연속적인 요소가 실제 인수 인 새로운 기본 배열이있는 새로운 유형의 조각이며 모두 할당 할 수 있어야합니다 T. 따라서 슬라이스의 길이와 용량은 p각 호출 사이트에 바인딩 된 인수 수이며 각 호출 사이트마다 다를 수 있습니다.

주어진 함수와 호출

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.