Go語言中切片slice的宣告與使用

sanqima發表於2020-10-01

一、切片slice的定義

    Go語言中的切片,是一種動態陣列,它是對陣列的擴充套件。

  • 與陣列相⽐,切⽚的⻓度是不固定的,可以追加元素,在追加時可能使切⽚的容量增⼤。
  • 切⽚本身沒有任何資料,它們只是對現有陣列的引⽤。
  • 切⽚與陣列相⽐,不需要設定⻓度,在[]中不⽤設定值,相對來說⽐較⾃由。
  • 從概念上⾯來說slice像⼀個結構體,這個結構體包含了三個元素:
    1)指標,指向陣列中slice指定的開始位置;
    2)⻓度,即slice的⻓度;
    3)最⼤⻓度,也就是slice開始位置到陣列的最後位置的⻓度。

二、切片的語法

2.1 宣告切片

    2.1.1 宣告⼀個未指定⻓度的陣列來定義切⽚

  • var identifier []type
  • 切⽚不需要說明⻓度;
  • 該宣告⽅式,且未初始化的切⽚為空切⽚。該切⽚預設為 nil,⻓度為 0。

    2.1.2 使⽤make()函式來建立切⽚:

  • var slice1 []type = make([]type, len)
  • 可以簡寫為: slice1 := make([]type, len)
  • 可以指定容量,其中capacity為可選引數: make([]T, length, capacity)

//mySlice.go

package main

import (
	"fmt"
)

func main() {
	//fmt.Println("Hello World!")
	//1)切片
	var numbers = make([]int, 3, 5)
	fmt.Printf("%T\n", numbers)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(numbers), cap(numbers), numbers)
}

效果如下:

Go語言中切片slice的宣告與使用
圖(1) 列印切片的長度、容量和資料元素

2.2 初始化

2.2.1 直接初始化切片

    s :=[] int {1,2,3 }

2.2.2 通過陣列擷取來初始化切⽚

   陣列: arr := [5]int {1,2,3,4,5}
  • 1)s := arr[:]
    切⽚中包含陣列所有元素
  • 2)s := arr[startIndex:endIndex]
    將arr中從下標startIndex到endIndex-1 下的元素建立為⼀個新的切⽚(前閉後開),⻓度為endIndex-startIndex
  • 3)s := arr[startIndex:]
    預設endIndex時將表示⼀直到arr的最後⼀個元素;
  • 4)s := arr[:endIndex]
    預設startIndex時將表示從arr的第⼀個元素開始。

2.2.3 通過切片擷取來初始化切片

    可以通過設定下限及上限來設定擷取切⽚ [lower-bound:upper-bound]
//mySlice2.go

package main

import (
	"fmt"
)

func printSlice(x []int) {
	fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

func main() {
	//fmt.Println("Hello World!")
	//1)切片
	// var numbers = make([]int, 3, 5)
	// fmt.Printf("%T\n", numbers)
	// fmt.Printf("len=%d cap=%d slice=%v\n", len(numbers), cap(numbers), numbers)

	//2)擷取切片
	numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
	printSlice(numbers)

	//列印原始切片
	fmt.Println("numbers== ", numbers)

	//列印子切片,從索引1到索引4,左閉右開,[1,4)
	fmt.Println("numbers[1:4]== ", numbers[1:4])

	//預設下限為0,[0,3)
	fmt.Println("numbers[:3]== ", numbers[:3])

	//預設上限為len(s),[4,len(s))
	fmt.Println("numbers[4:]== ", numbers[4:])

	//列印子切片,[0,2)
	number2 := numbers[:2]
	printSlice(number2)

	//列印子切片,[2,5)
	number3 := numbers[2:5]
	printSlice(number3)
}

    效果如下:

Go語言中切片slice的宣告與使用
圖(2) 通過擷取方法,來獲取切片

三、切片裡的len()和cap()函式

  • 切⽚的⻓度是切⽚中元素的數量。
  • 切⽚的容量是從建立切⽚的索引開始的底層陣列中元素的數量。
  • 切⽚是可索引的,並且可以由 len() ⽅法獲取⻓度, 切⽚提供了計算容量的⽅法 cap(), 可以測量切⽚最⻓可以達到多少。 [陣列計算cap()結果與len()相同]。
  • 切⽚實際的是獲取陣列的某⼀部分, len切⽚<=cap切⽚<=len陣列。
  • cap()的結果決定了切⽚擷取的注意細節。
    //mySlice02.go
// mySliceCap project main.go
package main

import (
	"fmt"
)

func main() {
	sliceCap()
}

func sliceCap() {
	arry := [...]string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
	fmt.Println("cap(arry)= ", cap(arry), arry)

	//擷取陣列,形成切片
	sli01 := arry[2:8]
	fmt.Printf("%T\n", sli01)
	fmt.Println("cap(sli01)= ", cap(sli01), sli01)

	sli02 := arry[4:7]
	fmt.Println("cap(sli02)= ", cap(sli02), sli02)

	//擷取切片,形成切片
	sli03 := sli01[3:9]
	fmt.Println("擷取sli01[3:9]後形成sli03: ", sli03)

	sli04 := sli02[4:7]
	fmt.Println("擷取sli02[4:7]後形成sli04: ", sli04)

	//切片是引用型別
	sli04[0] = "x"
	fmt.Print(arry, sli01, sli02, sli03, sli04)

}


    執行結果如下:

Go語言中切片slice的宣告與使用
圖(3) 切片裡的cap()函式

四、切片是引用型別

  • slice沒有⾃⼰的任何資料,它只是底層陣列的⼀個引⽤,對slice所做的任何修改都將反映在底層陣列中。
  • 陣列是值型別,⽽切⽚是引用型別。

    修改陣列的案例,如下:
//mySlice04.go

// mySliceCmp project main.go
package main

import (
	"fmt"
)

func main() {
	a := [4]float64{67.7, 89.8, 21, 78}
	b := []int{2, 3, 5}
	fmt.Printf("變數a -- 地址: %p, 型別: %T, 數值: %v, 長度: %d\n", &a, a, a, len(a))
	fmt.Printf("變數b -- 地址: %p, 型別: %T, 數值: %v, 長度: %d\n", &b, b, b, len(b))
	c := a
	d := b
	fmt.Printf("變數c -- 地址: %p, 型別: %T, 數值: %v, 長度: %d\n", &c, c, c, len(c))
	fmt.Printf("變數d -- 地址: %p, 型別: %T, 數值: %v, 長度: %d\n", &d, d, d, len(d))
	a[1] = 200
	fmt.Println("a= ", a, " c= ", c)
	d[0] = 100
	fmt.Println("b= ", b, " d= ", d)
}

    執行結果如下:

Go語言中切片slice的宣告與使用
圖(4)修改陣列裡的值
  • 修改切⽚數值
        當多個⽚共享相同的底層陣列時,每個元素所做的更改將在陣列中反映出來。
        修改切片裡的值,案例如下:
    //mySlice04.go
// mySliceChg project main.go
package main

import (
	"fmt"
)

func main() {
	//定義陣列
	arry := [3]int{1, 2, 3}

	//根據陣列擷取切片
	nums1 := arry[:]
	nums2 := arry[:]
	fmt.Println("arry= ", arry)

	nums1[0] = 100
	fmt.Println("arry= ", arry)

	nums2[1] = 200
	fmt.Println("arry= ", arry)

	fmt.Printf("變數arry  --地址: %p\n", &arry)
	fmt.Printf("變數nums1 --地址: %p\n", &nums1)
	fmt.Printf("變數nums2 --地址: %p\n", &nums2)
}

    執行結果如下:

Go語言中切片slice的宣告與使用
圖(5) 修改切片裡的值

相關文章