日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

golang中數組與切片的區別詳析_Golang

作者:周?-_- ? 更新時間: 2022-12-27 編程語言

一. Go 切片和 Go 數組定義

Go 切片:又稱動態數組,它實際是基于數組類型做的一層封裝。

Go 數組:數組是內置(build-in)類型,是一組同類型數據的集合,它是值類型,通過從 0 開始的下標索引訪問元素值。在初始化后長度是固定的,無法修改其長度。當作為方法的參數傳入時將復制一份數組而不是引用同一指針。數組的長度也是其類型的一部分,通過內置函數 len(array)獲取其長度。

二.切片與數組的區別

Go 數組與像 C/C++等語言中數組略有不同:

1. Go 中的數組是值類型,換句話說,如果你將一個數組賦值給另外一個數組,那么,實際上就是將整個數組拷貝一份。因此,在 Go 中如果將數組作為函數的參數傳遞的話,那效率就肯定沒有傳遞指針高了。

2. 數組的長度也是類型的一部分,這就說明[10]int和[20]int不是同一種數據類型。并且Go 語言中數組的長度是固定的,且不同長度的數組是不同類型,這樣的限制帶來不少局限性。

3. 而切片則不同,切片(slice)是一個擁有相同類型元素的可變長序列,可以方便地進行擴容和傳遞,實際使用時比數組更加靈活,這也正是切片存在的意義。而且切片是引用類型,因此在當傳遞切片時將引用同一指針,修改值將會影響其他的對象。

三. 切片使用

切片定義方式

  var a []int                    //nil切片,和nil相等,一般用來表示一個不存在的切片
   var b []int{}                //空切片,和nil不相等,一般用來表示一個空的集合
   var c []int{1, 2, 3}        //有3個元素的切片,len和cap都為3
   var d = c[:2]                //有2個元素的切片,len為2,cap為3
   var e = c[:2:cap(c)]        //有2個元素的切片,len為2,cap為3
   var f = c[:0]                //有0個元素的切片,len為0,cap為3
   var g = make([]int, 3)        //創建一個切片,len和cap均為3
   var h = make([]int, 3, 6)    //創建一個切片,len為3,cap為5
   var i = make([]int, 0, 3)    //創建一個切片,len為0,cap為3

從數組中切取切片

數組和切片是緊密相連的。切片可以用來訪問數組的部分或全部元素,而這個數組稱為切片的底層數組。切片的指針指向數組第一個可以從切片中訪問的元素,這個元素并不一定是數組的第一個元素。

一個底層數組可以對應多個切片,這些切片可以引用數組的任何位置,彼此之前的元素可以重疊。

slice 操作符 s[i:j] 創建了一個新的 slice,這個新的 slice 引用了 s 中從 i 到 j-1 索引位置的所有元素。

如果表達式省略了 i,那么默認是s[0:j];如果省略了 j,默認是s[i:len(s)];

  //創建一個數組
  months := [...]string{1:"January", /*...*/, 12: "December"}
  Q2 := months[4:7]
  summer := months[6:9]
  fmt.Println(Q2)                //["April" "May" "June"]
  fmt.Println(summer)            //["June" "July" "August"]

月份名稱字符串數組與其對應的兩個元素重疊的 slice 圖示

注意:切片與原數組或切片共享底層空間,修改切片會影響原數組或切片

迭代切片

切片可以用 range 迭代,但是要注意:如果只用一個值接收 range,則得到的只是切片的下標,用兩個值接收 range,則得到的才是下標和對應的值。

  //使用一個值接收range, 則得到的是切片的下標
   for i := range months {
       fmt.Println(i)        //返回下標 0 1 ... 12
   }
   //使用兩個值接收range,則得到的是下標和對應的值
   for i, v := range months {
       fmt.Println(i, v)     //返回下標0 1 ... 12 和 值 "" "January" ... "December"
   }

切片拷貝

使用copy內置函數拷貝兩個切片時,會將源切片的數據逐個拷貝到目的切片指向的數組中,拷貝數量取兩個切片的最小值。

例如長度為 10 的切片拷貝到長度為 5 的切片時,將拷貝 5 個元素。也就是說,拷貝過程中不會發生擴容。

copy 函數有返回值,它返回實際上復制的元素個數,這個值就是兩個 slice 長度的較小值。

切片擴容-append 函數

//通過append()函數可以在切片的尾部追加 N 個元素
  var a []int
  a = append(a, 1)                    // 追加一個元素
  a = append(a, 1, 2, 3)                // 追加多個元素
  a = append(a, []int{1, 2, 3}...)    // 追加一個切片,注意追加切片時后面要加...
//使用 append()函數也可以在切片頭部添加元素
  a = append([]int{0}, a...)            // 在開頭添加一個元素
  a = append([]int{1, 2, 3}, a...)    // 在開頭添加一個切片

注:從頭部添加元素會引起內存的重分配,導致已有元素全部復制一次。因此從頭部添加元素的開銷要比從尾部添加元素大很多

//通過 append()函數鏈式操作從中間插入元素
  a = append(a[:i], append([]int{x}, a[i:]...)...)        //在第i個位置上插入x
  a = append(a[:i], append([]int{1, 2, 3}, a[i:]...)...)    //在第i個位置上插入切片

使用鏈式操作在插入元素,在內層 append 函數中會創建一個臨式切片,然后將a[i:]內容復制到新創建的臨式切片中,再將臨式切片追加至a[:i]中。

通過 append()和 copy()函數組合從中間插入元素

使用這種方式可以避免創建過程中間的臨式切片,也可以做到從中間插入元素

  //中間插入一個元素
  a = append(a, 0)            //切片擴展一個空間
  copy(a[i+1:], a[i:])        //a[i:]向后移動一個位置
  a[i] = x                    //設置新添加的元素
  //中間插入多個元素
  a = append(a, x...)            //為x切片擴展足夠的空間
  copy(a[i+len(x):], a[i:])    //a[i:]向后移動len(x)個位置
  copy(a[i:], x)                //復制新添加的切片

使用此方式雖然稍顯復雜,但是可以減少創建中間臨時切片的開銷。

刪除元素

很遺憾,Go 語言中并沒有提供直接刪除指定位置元素的方式。不過根據切片的性質,我們可以通過巧妙的拼接切片來達到刪除指定數據的目的。

a = []int{1, 2, 3}
//刪除尾部元素
a = a[:len(a) - 1]                //刪除尾部一個元素
a = a[:len(a) - N]                //刪除尾部N個元素
//刪除頭部元素
a = [1:]                        //刪除開頭1個元素
a = [N:]                        //刪除開頭N個元素
//刪除中間元素
a = append(a[:i], a[i+1:]...)    //刪除中間一個元素
a = append(a[:i], a[i+N:]...)    //刪除中間N個元素

總結

原文鏈接:https://blog.csdn.net/m0_63593747/article/details/125708684

欄目分類
最近更新