數組就是一篇連續的內存,幾乎全部的計算機語言都有數組,只不過 Go 語言裏面的數組其實並不經常使用,這是由於數組是定長的靜態的,一旦定義好長度就沒法更改,並且不一樣長度的數組屬於不一樣的類型,之間不能相互轉換相互賦值,用起來多有不方便之處。git
切片是動態的數組,是能夠擴充內容增長長度的數組。當長度不變時,它用起來就和普通數組同樣。當長度不一樣時,它們也屬於相同的類型,之間能夠相互賦值。切片的便捷性讓數組的絕大多數應用領域都普遍地被取代了。github
不過也不能夠小瞧數組,在切片的底層實現中,數組是切片的基石,是切片的特殊語法隱藏了內部的細節,讓用戶不能直接看到內部隱藏的數組。切片不過是數組的一個包裝,給頑固的數組裝上了靈活的翅膀,讓石頭也能夠展翅飛翔。數組
僅僅是上面純文字的說明,讀者確定會感受很懵。下面讓咱們來看具體的實例。函數
咱們先試一下只申明類型,不賦初值。這時編譯器會給數組默認賦上「零值」。數組的零值就是全部內部元素的零值。性能
package main
import "fmt"
func main() {
var a [9]int
fmt.Println(a)
}
------------
[0 0 0 0 0 0 0 0 0]
複製代碼
下面咱們看看另外三種變量定義的形式, 效果都是同樣的ui
package main
import "fmt"
func main() {
var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var b [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
c := [8]int{1, 2, 3, 4, 5, 6, 7, 8}
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
---------------------
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9 10]
[1 2 3 4 5 6 7 8]
複製代碼
接下來咱們使用下標來簡單操做一下數組,這個數組裏存的是數字的平方值spa
package main
import "fmt"
func main() {
var squares [9]int
for i := 0; i < len(squares); i++ {
squares[i] = (i + 1) * (i + 1)
}
fmt.Println(squares)
}
--------------------
[1 4 9 16 25 36 49 64 81]
複製代碼
上面的代碼中咱們注意到可使用內置函數 len() 來直接獲取數組的長度。數組的長度是編譯期肯定的,當咱們使用 len() 函數訪問數組的長度屬性時,編譯器在背後偷偷把它替換成了整數值。3d
package main
import "fmt"
func main() {
var a = [5]int{1,2,3,4,5}
a[101] = 255
fmt.Println(a)
}
-----
./main.go:7:3: invalid array index 101 (out of bounds for 5-element array)
複製代碼
上面的代碼運行結果說明了 Go 語言會對數組訪問下標越界進行編譯器檢查。有一個重要的問題是,若是下標是一個變量,Go 是如何檢查下標越界呢?變量須要在運行時才能夠決定是否越界,Go 是如何辦到的呢?code
package main
import "fmt"
func main() {
var a = [5]int{1,2,3,4,5}
var b = 101
a[b] = 255
fmt.Println(a)
}
------------
panic: runtime error: index out of range
goroutine 1 [running]:
main.main()
/Users/qianwp/go/src/github.com/pyloque/practice/main.go:8 +0x3d
exit status 2
複製代碼
答案是 Go 會在編譯後的代碼中插入下標越界檢查的邏輯,因此數組的下標訪問效率是要打折扣的,比不得 C 語言的數組訪問性能。cdn
一樣的子元素類型而且是一樣長度的數組才能夠相互賦值,不然就是不一樣的數組類型,不能賦值。數組的賦值本質上是一種淺拷貝操做,賦值的兩個數組變量的值不會共享。
package main
import "fmt"
func main() {
var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var b [9]int
b = a
a[0] = 12345
fmt.Println(a)
fmt.Println(b)
}
--------------------------
[12345 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]
複製代碼
從上面代碼的運行結果中能夠看出賦值後兩個數組並無共享內部元素。若是數組的長度很大,那麼拷貝操做是有必定的開銷的,使用的時候必定須要注意。下面咱們嘗試使用不一樣長度的數組賦值會有什麼結果
package main
import "fmt"
func main() {
var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var b [10]int
b = a
fmt.Println(b)
}
--------------------------
./main.go:8:4: cannot use a (type [9]int) as type [10]int in assignment
複製代碼
能夠看出不一樣長度的數組之間賦值是禁止的,由於它們屬於不一樣的類型。
數組除了可使用下標進行遍歷以外,還可使用 range 關鍵字來遍歷,range 遍歷提供了下面兩種形式。
package main
import "fmt"
func main() {
var a = [5]int{1,2,3,4,5}
for index := range a {
fmt.Println(index, a[index])
}
for index, value := range a {
fmt.Println(index, value)
}
}
------------
0 1
1 2
2 3
3 4
4 5
0 1
1 2
2 3
3 4
4 5
複製代碼
考慮到切片的內容太多,咱們將獨立一節專門講解切片,下一節將是 Go 語言的極有價值的一節,讀者必定要努力搞清楚每個細節。
掃一掃上面的二維碼,閱讀《快學 Go 語言》更多章節