在任何一門語言裡,數組應該都是非常基礎的類型了,使用率當然也應該是很高的。go不但提供了數組,而且還在數組這個類型之上加了一層封裝,這個封裝也就是slice。
go的陣列變數(也就是數組名)是真真實實的數組,而不是一個指向數組記憶體起始位置的指標,也不能和同類型的指標進行轉化,這一點嚴重不同於C語言; C語言主要還是類型系統太弱了,因此很多的資料最終都退化為指標的方式來訪問。
go的數組定義:
var a [10]intvar a = [10]int{0,1,2,3,4,5,6,7,8,9}var a = [...]int{0,1,2,3,4,5,6,7,8,9}var a = [2][2]int{[2]int{1,1}, [2]int{2,2}}var a = [2][2]int{{1,1}, {2,2}}
由上面的數組定義可以看出,go的數群組類型由兩部分組成——類型和長度,二者缺一不可。數組本來就是一Block Storage相同類型元素的連續記憶體空間,因此決定一個數組的類型,必然需要決定其儲存元素的類型以及儲存多少個元素。這一點在所有語言中貌似都是相同的,沒有一個異類出現。
前文提到slice是在數組之上進行的一層封裝,因此,每個slice的背後都有一個苦逼的數組; 就好比一個囂張跋扈的女人背後總有一個苦逼的好男人。我覺得Slice也挺囂張的,總是可以隨心所欲的操縱背後的數組。
下面看看Slice究竟長什麼樣子:
var a = [10]int{0,1,,2,3,4,5,6,7,8,9}var s1 = a[0:5]var s2 = a[0:]var s3 = a[:]
可以看出slice是可以隨心所欲的表示一個數組上的一個或者一段元素,更關鍵的是slice不是一個實值型別,而是一個參考型別,就好比指標一樣,對slice取得的元素進行寫操作實際是影響到了底層的數組層,slice真的只是一層薄薄的操作封裝罷了。因此,slice有一個重要的用途就是作為函數的參數,就這可以避免直接傳遞數組而導致整個數組發生一次記憶體拷貝。
go編程中,倡導用slice對數組進行操作,而不是直接操作裸的數組,因為slice看上去更加的優雅,特性也更貼近C語言的指標。
slice也不是go的專利,支援這個特性的語言多了,至少python的list是支援這樣的分區操作的。仔細觀察能夠發現近幾年出現的這些動態語言都有著一些傳統語言所不具備的優秀特性,go不但有著這樣一些特性,並且還是編譯型的靜態語言。這也說明軟體生產力也在進步了,但很大一部分程式員貌似卻不想挪動自己的腳步,淺嘗一下新鮮的味道,特別是一幫有情結的C程式員,這裡也包括我自己,呵呵。
再補充一段展示數組和Slice關係的代碼:
package mainimport "fmt"func main() { a := []int{0,1,2,3,4,5,6,7,8,9} s := a[0:5] Print(a, "a") Print(s, "s") s1 := append(s, 0) fmt.Printf("=================\n") Print(a, "a") Print(s, "s") Print(s1, "s1")}func Print(o []int, name string) { fmt.Printf("%s: ", name) for _, v := range o { fmt.Printf("%d ", v) } fmt.Printf("\n")}
運行結果:
a: 0 1 2 3 4 5 6 7 8 9
s: 0 1 2 3 4
=================
a: 0 1 2 3 4 0 6 7 8 9
s: 0 1 2 3 4
s1: 0 1 2 3 4 0
這段代碼是為了加深自己的理解而做的實驗,我想還是可以看出一點端倪來的。
備忘:go語言學習筆記系列只是自己隨心所記的一點筆記和感悟,不是教材之類。