【Go學習筆記4】切片

zhongzhong05發表於2017-12-10

切片

go語言中的切片,類似於動態陣列的概念。因為陣列的長度不可變,那麼對於可變長度的資料,就需要使用切片來儲存。需要注意的是,切片的底層任然是使用陣列來儲存的,只不過切片當中有一個變數,是指向底層陣列的指標(學過C語言的同學應該知道指標的概念)。

切片的資料結構

|-----|-----|-----|

| 地址指標 |長度 | 容量 |

包括3個屬性,第一個是指向底層儲存資料的陣列的指標,第二個是當前切片的長度,第三個是切片最大可以容納的元素個數。

切片宣告

使用make函式建立切片:

slice := make([]string,5)
複製程式碼

上面的程式碼表示建立一個字串切片,切片的長度和容量都是5個元素。

  • 長度就是當前切片中擁有的元素個數
  • 容量表示切片最大容許擁有的元素個數

可以分別指定長度和容量大小

slice := make([]string,5,10)
複製程式碼

上面的程式碼表示,建立一個大小為5,容量為10的字串切片。

注意:長度不能大於容量,否則會在編譯的時候報錯。

切片字面量

另一種宣告切片的方式是使用切片字面量:

slice := []string{"one","two","three"}
複製程式碼

上面的程式碼表示,建立一個長度和容量都為3的字串切片。這種方式和陣列的唯一區別就是[]中沒有數字,如果裡面指定了數字的話,建立的就是陣列,而不是切片。

slice := []bool{false,true,false}
複製程式碼

上面的程式碼表示,建立一個長度和容量都為3的boolean切片。

空切片和nil切片

package main

import (
	"fmt"
)

func main(){
	var slice []string

	fmt.Println(slice == nil)
}
//true
複製程式碼

上面的程式碼表示建立一個nil切片,此時slice的值為nil,表示變數宣告瞭但是沒有初始化。

package main

import (
	"fmt"
)

func main(){
	slice := []string{}

	fmt.Println(slice == nil)
}
//false
複製程式碼

上面的程式碼表示建立了一個空切片,空切片的長度和容量都是0,但是slice的值

package main

import (
	"fmt"
)

func main(){
	slice := []string{}
	slice = append(slice,"one")
	fmt.Println(slice)
}
//[one]
複製程式碼
package main

import (
	"fmt"
)

func main(){
	var slice []string
	slice = append(slice,"one")
	fmt.Println(slice)
}
//[one]
複製程式碼

看上面的兩段程式碼,奇怪的是,nil切片和空切片都可以使用append函式對切片新增元素,但是在上面的程式碼中nil的切片slice=nil,而空切片slice!=nil。這通常可以理解為nil切片表示一個不存在的切片,而空切片表示的是切片存在,但是切片不包含任何元素。然而對於兩者的append操作,效果卻是一樣的。

使用切片

slice := []string{"one","two"}
slice[0] = "newOne"
複製程式碼

上面的程式碼表示修改切片中第一個元素的值為"newOne"。會發現切片修改和陣列的修改形式是一樣的。更加體現了切片的底層是陣列的這個設計。

slice[3] = "three"
//runtime error: index out of range
複製程式碼

嘗試將上面的切片修改第4個值,會出錯。因為上面的切片長度和容量都是2。

package main

import (
	"fmt"
)

func main(){
	slice := []string{"one","two"}
	slice[0] = "newOne"

	//使用append增加元素
	slice = append(slice,"three")

	fmt.Println(slice)
}
//[one two three]
複製程式碼

上面的程式碼表示向slice中新增一個元素。此時切片的長度=3,容量=4。

注意:在向切片中追加元素的時候,如果切片容量不夠,會自動擴充切片的容量,當切片的容量小於1000的時候,總是會成倍的增加容量,如果超過1000,則會在原來容量的基礎上乘以1.25。

package main

import (
	"fmt"
)

func main(){
	slice1 := []int{1,2,3,4}
	slice2 := []int{5,6,7,8}
  //將切片slice2中的所有元素追加到slice1中
	slice1 = append(slice1,slice2...)

	fmt.Println(slice1)
}
//[1 2 3 4 5 6 7 8]
複製程式碼

看到上面的程式碼,有沒有發現和js的陣列的concat操作是一樣的效果?

從切片建立切片

package main

import (
	"fmt"
)

func main(){
	slice := []int{1,2,3,4,5}

	//從slice中建立一個新的切片
	slice2 := slice[0:2:3]

	fmt.Println(slice2)
}
//[1 2]
複製程式碼

上面的程式碼表示從切片中建立切片,slice[0:2:3]第一個0表示起始位置,第二個2表示從新切片中包含的元素個數,第三個3表示新切片的容量。第三個值也可以不指定,如果不指定,新切片的容量=slice切片的容量-起始位置(這裡是0)

切片遍歷

package main

import (
	"fmt"
)

func main(){
	slice1 := []int{1,2,3,4}
	slice2 := []int{5,6,7,8}
	slice1 = append(slice1,slice2...)

	for index , value := range slice1{
		fmt.Println("index=",index,",value=",value)
	}
}
// index= 0 ,value= 1
// index= 1 ,value= 2
// index= 2 ,value= 3
// index= 3 ,value= 4
// index= 4 ,value= 5
// index= 5 ,value= 6
// index= 6 ,value= 7
// index= 7 ,value= 8
複製程式碼

上面的程式碼使用range關鍵字來遍歷切片,range在每一次的迭代中返回兩個變數,第一個表示當前操作的元素的位置索引,第二個表示當前的元素值。

package main

import (
	"fmt"
)

func main(){
	slice1 := []int{1,2,3,4}
	slice2 := []int{5,6,7,8}
	slice1 = append(slice1,slice2...)

	for index :=0 ; index < len(slice1) ; index++{
		fmt.Println("index=",index,",value=",slice1[index])
	}
}
// index= 0 ,value= 1
// index= 1 ,value= 2
// index= 2 ,value= 3
// index= 3 ,value= 4
// index= 4 ,value= 5
// index= 5 ,value= 6
// index= 6 ,value= 7
// index= 7 ,value= 8
複製程式碼

上面的程式碼使用傳統的for迴圈來遍歷切片。

相關文章