in -go言語スライシングの詳細な理解:共有メモリとトラップ
append()
こんにちはみんな!私のブログへようこそ。あなたがここにいるなら、あなたはちょうどゴランと接触したかもしれません、またはあなたは経験豊富な開発者であり、あなたはセクションの内部作業原則を理解したいです。始めましょう!
の一般的なトラップを避け、メモリを共有するためにスライスする方法をよりよく理解しましょう。
append()
スライスには、インデックス作成と長さの両方など、アレイといくつかの類似点がありますが、データ管理方法は異なります。スライスは、実際にスライスのデータを保存する基礎となる配列への参照として機能します。本質的に、スライスは、配列の一部またはすべての要素のビューを提供します。したがって、スライスを作成するとき、GOはスライスした要素/データの作成の下部配列を自動的に処理します。
スライスされた共有メモリ配列は連続的なメモリブロックですが、スライスを興味深いものにしているのは、このメモリを引用する方法です。スライスの構造を分解しましょう:
スライスを作成すると、3つのコンポーネントが含まれています。 基礎となる配列を指している
詩スライシングの長さ(それに含まれる要素の数)
<code class="language-go">type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }</code>
容量(増加する必要がある前に含めることができる要素の数)
len
cap
。既存のGO言語スライシングからサブスライスを取得すると、新しいサブスライスの
容量は、サブセクションからの元のスライスの残りの容量によって決定されます。少し分解しましょう:
アレイからスライスを作成する場合、スライスの長さは元々含まれていた要素の数であり、その容量は、成長する必要がある前に含めることができる要素の総数です。
既存のスライスからサブスライスを取得した場合:
<code class="language-go">type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }</code>
subslice := original[1:4]
subslice
容量subslice
trap!
未使用の容量共有append()
サブスライシングの容量
append()
この例を考えてみましょう:
容量は4です(元のスライスの端まで成長できます)。 60、70からを追加すると、元のスライスの余剰容量を使用します。
と
は、同じ基礎となる配列を共有するため、これらの変更を反映しています。<code class="language-go">package main import "fmt" func main() { // 创建一个具有初始值的切片 original := []int{1, 2, 3, 4, 5} // 创建一个子切片——两个切片共享相同的底层数组! subslice := original[1:3] fmt.Println("未修改的子切片:", subslice) // 输出 => 未修改的子切片: [2 3] // 修改子切片 subslice[0] = 42 fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5] fmt.Println("修改后的子切片:", subslice) // 输出 => 修改后的子切片: [42 3] }</code>
subslice
基礎となる配列に十分な容量があるため、操作は元のスライスを変更しました。ただし、容量の許可を超える容量の範囲または追加要素の追加要素を超える場合、GOはサブセクションの新しい配列を割り当てて、元のスライスとの共有を破壊します。
subslice
original
容量を明確にしますsubslice
append()
主な利点は次のとおりです
<code class="language-go">func main() { // 原始切片 original := []int{1, 2, 3, 4, 5} // 创建一个子切片 subslice := original[1:4] // 指向元素 2, 3, 4 fmt.Println("子切片:", subslice) // 输出 => 子切片: [2 3 4] fmt.Println("子切片的长度:", len(subslice)) // 输出 => 子切片的长度: 3 fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 子切片的容量: 4 }</code>
ii。これは、元のファイルを共有する代わりに、ファイルのコピーのようなものです。 append()
完全なスライス式を使用します
<code class="language-go">func main() { original := []int{1, 2, 3, 4, 5} subslice := original[1:3] // 指向元素 2, 3 fmt.Println("追加前原始切片:", original) // 输出 => [1 2 3 4 5] fmt.Println("追加前子切片:", subslice) // 输出 => [2 3] fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 4 // 在容量范围内追加到子切片 subslice = append(subslice, 60, 70) // 追加到子切片后打印 fmt.Println("追加后原始切片:", original) // 输出 => [1 2 3 60 70] fmt.Println("追加后子切片:", subslice) // 输出 => [2 3 60 70] }</code>
iデータ保護:元のデータは変更されていません。
II:入力に対する関数の効果は非表示になりますiii:処理プロセス中、元のデータは他のゴルウチンで安全に使用できます
覚えておいてください:
append()
サブスライス要素の要素を容量に追加すると、親のスライスのデータが変更されます。 <code class="language-go">type slice struct { array unsafe.Pointer // 指向底层数组的指针 len int // 切片中的元素数量 cap int // 底层数组的容量 }</code>
このリソースは役立つと思いますか?質問はありますか?それともエラーやタイプミスを見つけましたか?コメントにフィードバックを残してください。
以上がスライスとサブスライスに行く:共有されたメモリを理解し、 `append()`落とし穴を回避するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。