Golangラーニングロード-スライス(スライス)を理解するための記事

スライスの基本的な紹介

スライス自体は、動的配列または配列ポインターではありません。その内部データ構造は、ポインターを介して基になる配列を参照し、関連する属性を設定して、データの読み取りおよび書き込み操作を指定された領域に制限します。スライス自体は読み取り専用オブジェクトであり、その動作メカニズムは配列ポインターのカプセル化に似ています。

スライスは配列の連続セグメントへの参照であるため、スライスは参照型です(したがって、C / C ++の配列型、またはPythonのリスト型に似ています)。このセグメントは、配列全体、または開始インデックスと終了インデックスで識別されるアイテムのサブセットにすることができます。終了インデックスで識別される項目はスライスに含まれないことに注意してください。スライスは、配列へのポインタを備えた動的ウィンドウを提供します。

特定のアイテムのスライスインデックスは、関連する配列の同じ要素のインデックスよりも小さい場合があります。配列とは異なり、スライスの長さは実行時に変更できます。最小値は0、最大値は関連する配列の長さです。スライスは可変長の配列です。

スライス定義の基本構文:

var 切片名[]类型
如:var a[]int

スライスのクイックスタート

package main

import(
	"fmt"
)

func main(){
    
    

	var arr [5]int = [...]int{
    
    5,4,3,2,1}

	//定义一个切片
	//引用arr数组的起始下标为1,最后的下标为3(但不包括3)
	slice := arr[1:3]
	fmt.Println("arr=",arr)
	fmt.Println("slice 的元素是 =",slice)
	fmt.Println("slice 的元素个数 =",len(slice))
	fmt.Println("slice 的容量 =",cap(slice))//切片的容量是可以动态变化的

}

演算結果:
ここに画像の説明を挿入

メモリ形式でスライス

スライスのメモリレイアウト:
ここに画像の説明を挿入
説明:

  • スライスは参照型です
  • 下から見ると、スライスは実際にはデータ構造(構造体構造)です
type slice struct{
    
    
   ptr *[2] int
   len int
   cap int
}

ゼロスライスと空のスライス

ゼロスライスと空のスライスも一般的に使用されます。

ニルスライス

var slice []int

ここに画像の説明を挿入
Nilスライスは、多くの標準ライブラリや組み込み関数で使用されています。存在しないスライスを記述する場合は、nilスライスが必要です。たとえば、関数で例外が発生した場合、返されるスライスはnilスライスです。nilスライスポインタはnilを指します。

空のスライス

空のスライスは通常、空のコレクションを表すために使用されます。たとえば、データベースクエリが見つからない場合は、空のスライスを返すことができます。

slice := make([]int, 0)
slice := []int{
    
    }

ここに画像の説明を挿入
空のスライスとnilスライスの違いは、空のスライスが指すアドレスはnilではなく、メモリアドレスを指しますが、メモリスペースを割り当てないことです。つまり、基になる要素には0個の要素が含まれます。

説明する必要がある最後のポイントはです。nilスライスまたは空のスライスのどちらを使用するかに関係なく、組み込み関数のappend、len、およびcapを呼び出した場合の効果は同じです。

スライスの使用

方法1

スライスを定義してから、前の場合と同様に、作成された配列をスライスが参照するようにします。

func main(){
    
    

	var arr [5]int = [...]int{
    
    5,4,3,2,1}

	//定义一个切片
	//引用arr数组的起始下标为1,最后的下标为3(但不包括3)
	slice := arr[1:3]
	fmt.Println("arr=",arr)
	fmt.Println("slice 的元素是 =",slice)
	fmt.Println("slice 的元素个数 =",len(slice))
	fmt.Println("slice 的容量 =",cap(slice))//切片的容量是可以动态变化的
}

方法2

makeを使用してスライスを作成します。

基本構文:

var 切片名 []type = make([]type,len,[cap])

パラメータの説明:

  • typeはデータ型です
  • len:サイズ
  • cap:スライス容量を指定します。割り当てられている場合はオプションで、cap> = lenが必要です。

ケースプレゼンテーション

package main

import(
	"fmt"
)

func main(){
    
    

   var slice []int = make([]int ,5,10)
   slice[1] = 10
   slice[2] = 20
   fmt.Println(slice)
   fmt.Println("slice的size =",len(slice))
   fmt.Println("slice的cap =",cap(slice))
}

演算結果:
ここに画像の説明を挿入
説明:

  • スライスのサイズと容量は、makeでスライスを作成することで指定できます
  • スライスの各要素に値が割り当てられていない場合は、デフォルト値が使用されます。
  • makeメソッドによって作成されたスライスに対応する配列は、makeの最下層によって維持され、外部からは見えません。つまり、各要素にはスライスを介してのみアクセスできます。

方法3

スライスを定義し、特定の配列を直接指定します。使用の原則はmakeの方法と似ています。

場合:

package main

import(
	"fmt"
)

func main(){
    
    

   var slice []string = []string{
    
    "Casey","Lily","Sally"}
   fmt.Println(slice)
   fmt.Println("slice的size =",len(slice))
   fmt.Println("slice的cap =",cap(slice))
}

演算結果:
ここに画像の説明を挿入

方法1と方法2の違い(インタビュー)

  • 方法1は、配列を直接参照することです。この配列は既存のものであり、プログラマーに表示されます。
  • 方法2は、makeを介してスライスを作成することです。また、makeは配列を作成します。この配列は、プログラマーには見えない最下位レベルのスライスによって維持されます。
    make作成スライスの概略図:
    ここに画像の説明を挿入

スライストラバーサル

スライスのトラバーサルは配列のトラバーサルと同じです。forループをトラバースする方法とfor-range構造をトラバースしてスライスをトラバースする方法は2つあります。
ケースのデモンストレーション:

package main

import(
	"fmt"
)

func main(){
    
    

  var slice []string = []string{
    
    "Casey","Lily","Sally"}
  //常规for循环遍历切片
  for i := 0; i < len(slice); i++{
    
    
	  fmt.Printf("slice[%d] = %v\n", i, slice[i])
  }

  //使用for-range结构遍历切片

  for index, value := range slice{
    
    
	  fmt.Printf("i = %v, v = %v\n", index, value)
  }

}

演算結果:
ここに画像の説明を挿入

追加組み込み関数は、スライスを動的に追加します

ケースプレゼンテーション

package main

import(
	"fmt"
)

func main(){
    
    

  var slice []string = []string{
    
    "Casey","Lily","Sally"}
  //通过append内置函数,可以对切片进行动态追加 
  slice = append(slice,"Jerry","Tom")
  fmt.Println("slice =",slice)

  //通过append将切片slice追加给slice
  slice = append(slice,slice...)
  fmt.Println("slice =",slice)

}

演算結果:
ここに画像の説明を挿入

基礎となる分析

回路図:
ここに画像の説明を挿入
説明:

  • スライス追加操作の本質は、配列を拡張することです
  • 最下層に移動すると、新しい配列newArrが作成されます(インストールおよび拡張後のサイズ)
  • スライスの元の要素が新しい配列newArrにコピーされ、スライスがnewArrに再参照されます。

スライスコピー操作

スライスは、コピー組み込み関数を使用してコピーを完了します。
場合:

package main

import(
	"fmt"
)

func main(){
    
    

  var slice []string = []string{
    
    "Casey","Lily","Sally"}
  var slice1 = make([]string,5)
  copy(slice1,slice)
  fmt.Printf("slice = %v\n",slice)
  fmt.Printf("slice1 = %v\n", slice1)

  var slice2 []int = []int{
    
    10,20,30}
  var slice3 = make([]int,5)
  copy(slice3,slice2)
  fmt.Printf("slice2 = %v\n",slice2)
  fmt.Printf("slice3 = %v\n", slice3)

}

演算結果:
ここに画像の説明を挿入
説明:

  • copy(para1、para2)パラメーターのデータ型はsliceです。
  • 上記のコードによると、sliceとslice、slice2とslice3のデータ空間は独立しており、相互に影響を及ぼしません。

スライス使用上の注意

  • スライスが初期化されると、varスライス= arr [startIndex:endIndex]
    説明:arr配列の添え字をstartIndexとして、添え字がendIndex(endIndexを含まない)の要素を取得します。
  • スライスが初期化されても、境界を越えることはできません。範囲は0〜len(arr)-1ですが、動的に拡大できます。
var slice = arr[0:end] 可简写 var slice = arr[:end]
var slice = arr[start:len(arr)]可简写var slice = arr[start:]
var slice = arr[0:len(str)] 可简写 var slice = arr[:]
  • capは、スライスの容量、つまり最大で格納できる要素の数をカウントするために使用される組み込み関数です。
  • スライスが定義された後は、それが空であり、配列を参照するか、スライスが使用するためのスペースを作成する必要があるため、使用できません。
  • スライスはスライスを続行できます。
    場合:
package main

import(
	"fmt"
)

func main(){
    
    

  var slice []string = []string{
    
    "Casey","Lily","Sally"}
  slice1 := slice[0:2]
  //slice 和 slice1指向的数据空间是同一个,因此slice[1] = "abc"
  slice1[1] = "abc"

  fmt.Println("slice =",slice)
  fmt.Println("slice1 =",slice1)

}

演算結果:
ここに画像の説明を挿入

  • スライスは参照型であり、渡されると、参照パスメカニズムに従います。

おすすめ

転載: blog.csdn.net/weixin_44736475/article/details/113999771