それでは、Go の最も多用途で不可欠な機能の 1 つであるスライスについて詳しく見ていきましょう。別の言語から来た人は、スライスを配列と同じように考えるかもしれません。そして、はい、それらにはいくつかの類似点がありますが、スライスはより多くのパワー、柔軟性、そして Go 特有の魔法をテーブルにもたらします。 ?
Go では、スライスは要素のリスト (配列など) を操作できるタイプですが、動的であるため、必要に応じて拡大および縮小できます。配列の場合のように、事前に固定長を指定する必要はありません。これらは内部で配列によってサポートされていますが、より詳細な制御が可能になります。これらは、配列のよりクールで柔軟な兄弟であると考えてください。
つまり、Go のスライスは実際には、基礎となる配列に対する「ウィンドウ」です。このウィンドウのサイズは拡大または縮小することで変更でき、ケーキをスライスするのと同じくらいスムーズです。 ?
スライスを作成しますか?
スライスの作成は非常に簡単です:
// Using a literal numbers := []int{1, 2, 3, 4, 5} // Using the make function sliceOfStrings := make([]string, 5) // a slice of 5 strings, each
空の文字列に初期化されました
make を使用すると、特定の長さのスライスを作成するように Go に指示しますが、そのスライスは、Go が管理する配列によって裏付けられます。したがって、メモリ割り当ての詳細について心配する必要はありません。 ?
スライスの 2 つの重要な概念は、長さと容量です。長さは現在スライス内にある要素の数であり、容量はサイズ変更が必要になる前に保持できる要素の総数です。
numbers := []int{1, 2, 3} fmt.Println(len(numbers)) // 3 fmt.Println(cap(numbers)) // 3 (same as length here)
アイテムの追加を開始すると、容量がいっぱいになるたびに Go の容量が 2 倍になるため、上限に達することを心配する必要はありません。
numbers = append(numbers, 4) fmt.Println(len(numbers)) // 4 fmt.Println(cap(numbers)) // probably 6 now, depending on Go’s growth
パターン
スライスへの追加: Go の組み込みマジック ?✨
Go の append 関数を使用すると、要素をスライスに追加するのと同じくらい簡単です。 1 つ以上の要素を一度に追加でき、Go がすべてのサイズ変更とメモリ関連を処理します。
numbers := []int{1, 2, 3} numbers = append(numbers, 4, 5, 6) // Adding multiple elements at once fmt.Println(numbers) // [1 2 3 4 5 6]
この自動サイズ変更機能により、特にリストがどれくらい大きくなるかわからない場合に、スライスが非常に便利になります。
Go でのスライスは、実際に物事が本当に楽しいところです。要素をコピーせずに、既存のスライスの「サブスライス」を作成できます。
numbers := []int{10, 20, 30, 40, 50} subSlice := numbers[1:4] // Just takes a "slice" of the original slice fmt.Println(subSlice) // [20 30 40]
numbers[1:4] では、最初のインデックス (1) は包括的であり、最後のインデックス (4) は排他的です。最終的に要素は位置 1、2、3 にありますが、4 にはありません。
このサブスライスは元のスライスと同じ基になる配列を共有しているため、一方を変更するともう一方にも影響します。
subSlice[0] = 25 fmt.Println(numbers) // [10 25 30 40 50] fmt.Println(subSlice) // [25 30 40]
意図しない変更を避けるために、コピーを使用してスライスの独立したバージョンを作成できます。
// Using a literal numbers := []int{1, 2, 3, 4, 5} // Using the make function sliceOfStrings := make([]string, 5) // a slice of 5 strings, each
現在の容量より大きいスライスが必要な場合、追加はバックグラウンドで新しいより大きな配列を自動的に作成し、すべてをコピーします。これは信じられないほど効率的で、スライスを素晴らしいものにする大きな部分を占めています。 append が新しい配列を作成すると、以前の 2 倍の容量が割り当てられるため、拡張する余地が得られます!
これが Go のちょっとした秘密です。スライスは非常に強力ですが、注意しないとメモリ リークを引き起こすことがあります。スライスは同じ基になる配列を参照するため、配列のごく一部しか使用していない場合でも、配列がメモリ内に残る可能性があります。
例:
numbers := []int{1, 2, 3} fmt.Println(len(numbers)) // 3 fmt.Println(cap(numbers)) // 3 (same as length here)
このような場合は、コピーを使用して、必要なデータのみを含む完全に独立したスライスを作成し、残りのメモリを解放するのが最善です。
numbers = append(numbers, 4) fmt.Println(len(numbers)) // 4 fmt.Println(cap(numbers)) // probably 6 now, depending on Go’s growth
複数の次元が必要ですか?多次元スライスも作成できます。これはグリッドやテーブルなどに便利です。スライスのスライスを宣言するだけです:
numbers := []int{1, 2, 3} numbers = append(numbers, 4, 5, 6) // Adding multiple elements at once fmt.Println(numbers) // [1 2 3 4 5 6]
各「行」はそれ自体がスライスであるため、必要に応じて個別に拡張できます。
numbers := []int{10, 20, 30, 40, 50} subSlice := numbers[1:4] // Just takes a "slice" of the original slice fmt.Println(subSlice) // [20 30 40]
nil スライスは、単にまだ初期化されていないスライスです。長さと容量はゼロですが、パニックに陥ることなく追加などの関数を使用できます。
subSlice[0] = 25 fmt.Println(numbers) // [10 25 30 40 50] fmt.Println(subSlice) // [25 30 40]
nil スライスに追加すると、Go はそれを自動的に初期化します。しっかりと準備を整えるのは素晴らしいコツです。
落とし穴とベストプラクティス?
共有メモリに注意する: スライスは元の配列とメモリを共有することに注意してください。これはパフォーマンスには優れていますが、大きな配列の一部をスライスする場合は、メモリ内に不要なデータが保持されないよう注意してください。
サイズ変更に注意: 追加するとき、現在の容量がいっぱいの場合、Go は新しい基になる配列を作成する必要がある場合があります。これは、小さなサイズ変更を何度も行うより効率的ですが、大規模なデータセットを扱う場合はオーバーヘッドに注意してください。
時期尚早な最適化を避ける: Go は大量のメモリ割り当てとスライスによるサイズ変更を自動的に処理します。多くの場合、これらの詳細を細かく管理しようとすると、コードが煩雑になり、効率が低下する可能性があります。ほとんどの場合、Go のスライス メカニズムが正しいことを行うと信じてください。
以上がスライス: Go のバックボーン!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。