1. 程式人生 > >Go學習(4):陣列和切片

Go學習(4):陣列和切片

一、陣列(Array)

1.1 什麼是陣列

Go 語言提供了陣列型別的資料結構。
陣列是具有相同唯一型別的一組已編號且長度固定的資料項序列,這種型別可以是任意的原始型別例如整形、字串或者自定義型別。

陣列元素可以通過索引(位置)來讀取(或者修改),索引從0開始,第一個元素索引為 0,第二個索引為 1,以此類推。陣列的下標取值範圍是從0開始,到長度減1。

陣列一旦定義後,大小不能更改。這些性質和java中的陣列類似.

1.2 陣列的語法

宣告和初始化陣列

需要指明陣列的大小和儲存的資料型別。

var variable_name [SIZE] variable_type

示例程式碼:

var balance [10] float32
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

初始化陣列中 {} 中的元素個數不能大於 [] 中的數字。
如果忽略 [] 中的數字不設定陣列大小,Go 語言會根據元素的個數來設定陣列的大小:

var balance = []float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance[4] = 50.0

陣列的其他建立方式:

  var a [4] float32 // 等價於:var arr2 = [4]float32{}
  fmt.Println
(a) // [0 0 0 0] var b = [5] string{"ruby", "王二狗", "rose"} fmt.Println(b) // [ruby 王二狗 rose ] var c = [5] int{'A', 'B', 'C', 'D', 'E'} // byte fmt.Println(c) // [65 66 67 68 69] d := [...] int{1,2,3,4,5}// 根據元素的個數,設定陣列的大小 fmt.Println(d)//[1 2 3 4 5] e := [5] int{4: 100} // [0 0 0 0 100] fmt.Println(e) f :=
[...] int{0: 1, 4: 1, 9: 1} // [1 0 0 0 1 0 0 0 0 1] fmt.Println(f)

備註 :
Println :可以打印出字串,和變數
Printf : 只可以打印出格式化的字串,可以輸出字串型別的變數,不可以輸出整形變數和整形
當需要格式化輸出資訊時一般選擇 Printf,其他時候用 Println 就可以了

訪問陣列元素

float32 salary = balance[9]

示例程式碼:

package main

import "fmt"

func main() {
   var n [10]int /* n 是一個長度為 10 的陣列 */
   var i,j int

   /* 為陣列 n 初始化元素 */         
   for i = 0; i < 10; i++ {
      n[i] = i + 100 /* 設定元素為 i + 100 */
   }

   /* 輸出每個陣列元素的值 */
   for j = 0; j < 10; j++ {
      fmt.Printf("Element[%d] = %d\n", j, n[j] )
   }
}

執行結果:

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

陣列的長度

通過將陣列作為引數傳遞給len函式,可以獲得陣列的長度。

示例程式碼:

package main

import "fmt"

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    fmt.Println("length of a is",len(a))

}

執行結果:

length of a is 4

您甚至可以忽略宣告中陣列的長度並將其替換為…讓編譯器為你找到長度。這是在下面的程式中完成的。

示例程式碼:

package main

import (  
    "fmt"
)

func main() {  
    a := [...]int{12, 78, 50} // ... makes the compiler determine the length
    fmt.Println(a)
}

遍歷陣列:

package main

import "fmt"

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    for i := 0; i < len(a); i++ { //looping from 0 to the length of the array
        fmt.Printf("%d th element of a is %.2f\n", i, a[i])
    }
}

使用range遍歷陣列:

package main

import "fmt"

func main() {  
    a := [...]float64{67.7, 89.8, 21, 78}
    sum := float64(0)
    for i, v := range a {//range returns both the index and value
        fmt.Printf("%d the element of a is %.2f\n", i, v)
        sum += v
    }
    fmt.Println("\nsum of all elements of a",sum)
}

如果您只需要值並希望忽略索引,那麼可以通過使用_ blank識別符號替換索引來實現這一點。

for _, v := range a { //ignores index  
}

1.3 多維陣列

Go 語言支援多維陣列,以下為常用的多維陣列宣告語法方式:

var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type
var threedim [5][10][4]int

二維陣列
多維陣列可通過大括號來初始值。以下例項為一個 3 行 4 列的二維陣列:

a = [3][4]int{  
 {0, 1, 2, 3} ,   /*  第一行索引為 0 */
 {4, 5, 6, 7} ,   /*  第二行索引為 1 */
 {8, 9, 10, 11}   /*  第三行索引為 2 */
}
int val = a[2][3]

以上例項訪問了二維陣列 val 第三行的第四個元素。

遍歷二維陣列:

package main

import "fmt"

func main() {
   /* 陣列 - 5 行 2 列*/
   var a = [5][2]int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
   var i, j int

   /* 輸出陣列元素 */
   for  i = 0; i < 5; i++ {
      for j = 0; j < 2; j++ {
         fmt.Printf("a[%d][%d] = %d\n", i,j, a[i][j] )
      }
   }
}

1.4 陣列是值型別

陣列是值型別
Go中的陣列是值型別,而不是引用型別。這意味著當它們被分配給一個新變數時,將把原始陣列的副本分配給新變數。如果對新變數進行了更改,則不會在原始陣列中反映。

package main

import "fmt"

func main() {  
    a := [...]string{"USA", "China", "India", "Germany", "France"}
    b := a // a copy of a is assigned to b
    b[0] = "Singapore"
    fmt.Println("a is ", a)
    fmt.Println("b is ", b) 
}

執行結果:

a is [USA China India Germany France]  
b is [Singapore China India Germany France] 

類似地,當將陣列傳遞給函式作為引數時,它們將通過值傳遞,而原始陣列將保持不變。

向函式傳遞陣列

第一種

void myFunction(param [10]int)
{
.
.
.
}

第二種

void myFunction(param []int)
{
.
.
.
}
func getAverage(arr []int, int size) float32
{
   var i int
   var avg, sum float32  

   for i = 0; i < size; ++i {
      sum += arr[i]
   }

   avg = sum / size

   return avg;
}
package main

import "fmt"

func changeLocal(num [5]int) {  
    num[0] = 55
    fmt.Println("inside function ", num)

}
func main() {  
    num := [...]int{5, 6, 7, 8, 8}
    fmt.Println("before passing to function ", num)
    changeLocal(num) //num is passed by value
    fmt.Println("after passing to function ", num)
}

執行結果:

before passing to function  [5 6 7 8 8]  
inside function  [55 6 7 8 8]  
after passing to function  [5 6 7 8 8]  

陣列的大小是型別的一部分。因此[5]int和[25]int是不同的型別。因此,陣列不能被調整大小。不要擔心這個限制,因為切片的存在是為了解決這個問題。

package main

func main() {  
    a := [3]int{5, 78, 8}
    var b [5]int
    b = a //not possible since [3]int and [5]int are distinct types
}

二、切片(Slice)

2.1 什麼是切片

Go 語言切片是對陣列的抽象
Go 陣列的長度不可改變,在特定場景中這樣的集合就不太適用,Go中提供了一種靈活,功能強悍的內建型別切片(“動態陣列”),與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大

切片是一種方便、靈活且強大的包裝器。切片本身沒有任何資料。它們只是對現有陣列的引用。

切片與陣列相比,不需要設定長度,在[]中不用設定值,相對來說比較自由

從概念上面來說slice像一個結構體,這個結構體包含了三個元素:

  1. 指標,指向陣列中slice指定的開始位置
  2. 長度,即slice的長度
  3. 最大長度,也就是slice開始位置到陣列的最後位置的長度

2.2 切片的語法

定義切片

var identifier []type

切片不需要說明長度。
或使用make()函式來建立切片:

var slice1 []type = make([]type, len)
也可以簡寫為
slice1 := make([]type, len)
make([]T, length, capacity)

初始化

s[0] = 1
s[1] = 2
s[2] = 3
s :=[] int {1,2,3 } 
s := arr[startIndex:endIndex] 

將arr中從下標startIndex到endIndex-1 下的元素建立為一個新的切片(前閉後開),長度為endIndex-startIndex

s := arr[startIndex:] 

預設endIndex時將表示一直到arr的最後一個元素

s := arr[:endIndex] 

預設startIndex時將表示從arr的第一個元素開始

package main

import (  
    "fmt"
)

func main() {  
    a := [5]int{76, 77, 78, 79, 80}
    var b []int = a[1:4] //creates a slice from a[1] to a[3]
    fmt.Println(b)
}

2.3 修改切片

slice沒有自己的任何資料。它只是底層陣列的一個表示。對slice所做的任何修改都將反映在底層陣列中。

示例程式碼:

package main

import (  
    "fmt"
)

func main() {  
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println("array before",darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println("array after",darr) 
}

執行結果:

array before [57 89 90 82 100 78 67 69 59]  
array after [57 89 91 83 101 78 67 69 59]  

當多個片共享相同的底層陣列時,每個元素所做的更改將在陣列中反映出來。

示例程式碼:

package main

import (  
    "fmt"
)

func main() {  
    numa := [3]int{78, 79 ,80}
    nums1 := numa[:] //creates a slice which contains all elements of the array
    nums2 := numa[:]
    fmt.Println("array before change 1",numa)
    nums1[0] = 100
    fmt.Println("array after modification to slice nums1", numa)
    nums2[1] = 101
    fmt.Println("array after modification to slice nums2", numa)
}

執行結果:

array before change 1 [78 79 80]  
array after modification to slice nums1 [100 79 80]  
array after modification to slice nums2 [100 101 80]  

2.4 len() 和 cap() 函式

切片的長度是切片中元素的數量。切片的容量是從建立切片的索引開始的底層陣列中元素的數量。

切片是可索引的,並且可以由 len() 方法獲取長度
切片提供了計算容量的方法 cap() 可以測量切片最長可以達到多少

package main

import "fmt"

func main() {
   var numbers = make([]int,3,5)

   printSlice(numbers)
}

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

結果

len=3 cap=5 slice=[0 0 0]

空切片

一個切片在未初始化之前預設為 nil,長度為 0

package main

import "fmt"

func main() {
   var numbers []int

   printSlice(numbers)

   if(numbers == nil){
      fmt.Printf("切片是空的")
   }
}

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

結果

len=0 cap=0 slice=[]
切片是空的
package main

import "fmt"

func main() {
   /* 建立切片 */
   numbers := []int{0,1,2,3,4,5,6,7,8}   
   printSlice(numbers)

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

   /* 列印子切片從索引1(包含) 到索引4(不包含)*/
   fmt.Println("numbers[1:4] ==", numbers[1:4])

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

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

   numbers1 := make([]int,0,5)
   printSlice(numbers1)

   /* 列印子切片從索引  0(包含) 到索引 2(不包含) */
   number2 := numbers[:2]
   printSlice(number2)

   /* 列印子切片從索引 2(包含) 到索引 5(不包含) */
   number3 := numbers[2:5]
   printSlice(number3)

}

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

結果

len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=7 slice=[2 3 4]

2.5 append() 和 copy() 函式

append 向slice裡面追加一個或者多個元素,然後返回一個和slice一樣型別的slice
copy 函式copy從源slice的src中複製元素到目標dst,並且返回複製的元素的個數

append函式會改變slice所引用的陣列的內容,從而影響到引用同一陣列的其它slice。 但當slice中沒有剩
餘空間(即(cap-len) == 0)時,此時將動態分配新的陣列空間。返回的slice陣列指標將指向這個空間,而原
陣列的內容將保持