回答:
2番目のスライスの後にドットを追加します。
//---------------------------vvv
append([]int{1,2}, []int{3,4}...)
これは、他の可変関数と同じです。
func foo(is ...int) {
for i := 0; i < len(is); i++ {
fmt.Println(is[i])
}
}
func main() {
foo([]int{9,8,7,6,5}...)
}
foo()
上記の例では、is
パラメーターは元のスライスのコピーを保持しています。つまり、同じ基本的な配列lenおよびcapへの軽量参照のコピーを持っています。foo
関数がメンバーを変更した場合、変更は元のメンバーに表示されます。こちらがデモです。したがって、実際のオーバーヘッドは、スライスがまだない場合に新しいスライスfoo(1, 2, 3, 4, 5)
を作成is
することだけです。
可変個引数関数
append
は0個以上の値x
をs
typeの値に追加しますS
。これはスライス型である必要があり、結果のスライスもtypeで返しますS
。値x
はのタイプのパラメーターに渡されます。...T
ここT
で、はのエレメントタイプでS
あり、それぞれのパラメーター渡しルールが適用されます。特殊なケースとして、appendは、typeに割り当て可能な最初の引数を受け入れ、type[]byte
の2番目の引数のstring
後にを続け...
ます。このフォームは、文字列のバイトを追加します。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
です。の各呼び出しでf
、最後のパラメータに渡される引数は、[]T
連続する要素が実際の引数であるタイプの新しいスライスであり、すべてがタイプに割り当て可能でなければなりませんT
。したがって、スライスの長さは最後のパラメーターにバインドされた引数の数であり、呼び出しサイトごとに異なる場合があります。
あなたの質問に対する答えs3 := append(s2, s0...)
は、Goプログラミング言語仕様の例です。例えば、
s := append([]int{1, 2}, []int{3, 4}...)
他の回答には何もありませんが、ドキュメントの簡単な説明は、それらの例よりも簡単に理解できることがわかりました。
func append
func append(slice []Type, elems ...Type) []Type
追加組み込み関数は、要素をスライスの最後に追加します。十分な容量がある場合、宛先は新しい要素に対応するように再割り当てされます。そうでない場合は、新しい基本配列が割り当てられます。Appendは更新されたスライスを返します。したがって、多くの場合、スライス自体を保持する変数に追加の結果を格納する必要があります。slice = append(slice, elem1, elem2) slice = append(slice, anotherSlice...)
特殊なケースとして、次のようにバイトスライスに文字列を追加することは合法です。
slice = append([]byte("hello "), "world"...)
宛先スライス(追加先のスライス)に十分な容量がある場合、宛先を再スライスすることによって(追加するためにその長さを増やすように再スライスすることにより)追加が「インプレース」で行われることを指摘し、知っておくことが重要だと思います追加可能な要素に対応できます)。
これは、結果のスライスの長さを超える追加の要素がある大きな配列またはスライスをスライスすることによって宛先が作成された場合、それらが上書きされる可能性があることを意味します。
例として、次の例をご覧ください。
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]
a
長さの「バッキング」配列を作成しました10
。次に、x
このa
配列をスライスして宛先スライスを作成します。y
スライスは、複合リテラルを使用して作成され[]int{3, 4}
ます。ここでに追加y
するx
と、結果は期待どおりですが、[1 2 3 4]
驚くべきことは、バッキング配列a
も変更されたことx
です。10
これは、容量がis に追加y
するのに十分なため、バッキング配列も変更され、x
同じ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
@iczaの回答は重要な概念なので、@ iczaの回答を強調し、少し簡略化したいと思います。読者はスライスに慣れていると思います。
c := append(a, b...)
これは質問に対する有効な回答です。 しかし、後で別のコンテキストでコードのスライス「a」と「c」を使用する必要がある場合、これはスライスを連結する安全な方法ではありません。
説明するために、スライスではなく、基礎となる配列の観点から式を読み取ってみましょう。
「 'a'の(基礎となる)配列を取得し、それに配列 'b'の要素を追加します。配列 'a'に 'b'のすべての要素を含めるのに十分な容量がある場合-'c'の基になる配列は新しい配列にはなりません、実際には配列 'a'になります。基本的に、スライス 'a'は基礎となる配列 'a'のlen(a)要素を表示し、スライス 'c'は配列 'a'のlen(c)を表示します。
append()は必ずしも新しい配列を作成するわけではありません!これにより、予期しない結果が生じる可能性があります。Go Playgroundの例を参照してください。
スライスに新しい配列が割り当てられていることを確認したい場合は、常に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)
2つのスライスは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]
append([]int{1,2}, []int{3,4}...)
働くでしょう。...
パラメータに引数を渡します。
がtypeのf
最終パラメーターp
を持つ可変個の場合、の型...T
内f
はtype p
と同等[]T
です。
f
がの実際の引数なしで呼び出された場合p
、渡される値p
はnil
です。
それ以外の場合、渡される値は、[]T
連続する要素が実際の引数である新しい基本配列を持つタイプの新しいスライスであり、すべてがに割り当て可能でなければなりませんT
。したがって、スライスの長さと容量は、バインドされる引数の数であり、p
呼び出しサイトごとに異なる場合があります。
関数と呼び出しを考える
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
append()
可変個関数と、...
スライスから可変個個関数に複数の引数を渡すことができます。