Golang數(shù)據(jù)類型之?dāng)?shù)組
目錄
1、存儲方式
2、聲明與初始化
2.1 聲明語法
2.2 數(shù)組類型
2.3 數(shù)組默認(rèn)值
2.4 聲明并初始化
3、訪問與修改
4、指針數(shù)組
5、數(shù)組拷貝
6、數(shù)組遍歷
7、多維數(shù)組
8、數(shù)組作為函數(shù)參數(shù)

有過Python、JavaScript編程經(jīng)驗的人都知道其數(shù)組是動態(tài)的,可以隨需求自動增大數(shù)組長度,而Go里面的數(shù)組長度卻是固定的,無法擴大或者縮小
但Go中也有類似的動態(tài)"數(shù)組",稱為切片slice
Go中的數(shù)組是slice和map兩種數(shù)據(jù)類型的基礎(chǔ),這兩種數(shù)據(jù)類型的底層都是通過數(shù)組實現(xiàn)的
1、存儲方式
當(dāng)在Go中聲明一個數(shù)組之后,會在內(nèi)存中開辟一段固定長度的、連續(xù)的空間存放數(shù)組中的各個元素,這些元素的數(shù)據(jù)類型完全相同,可以是內(nèi)置的簡單數(shù)據(jù)類型(int、string等),也可以是自定義的struct`結(jié)構(gòu)體類型
固定長度:這意味著數(shù)組不可增長、不可縮減。想要擴展數(shù)組,只能創(chuàng)建新數(shù)組,將原數(shù)組的元素復(fù)制到新數(shù)組 連續(xù)空間:這意味可以在緩存中保留的時間更長,搜索速度更快,是一種非常高效的數(shù)據(jù)結(jié)構(gòu),同時還意味著可以通過數(shù)值 index的方式訪問數(shù)組中的某個元素數(shù)據(jù)類型:意味著限制了每個 block中可以存放什么樣的數(shù)據(jù),以及每個block可以存放多少字節(jié)的數(shù)據(jù)
例如,使用下面的語句聲明一個長度為4的int類型的數(shù)組,那么這個數(shù)組最多只能存放4個元素,且所有元素都只能是int類型。同時,還為這個數(shù)組做了初始化
array := [4]int{3, 1, 4,1 }
2、聲明與初始化
2.1 聲明語法
Go語言數(shù)組聲明需要指定元素類型及元素個數(shù),語法格式如下
var variable_name [SIZE] variable_type
比如聲明一個長度為5, 類型是float64的數(shù)組
var arrayf [5]float64
2.2 數(shù)組類型
雖然稱呼數(shù)組為int類型的數(shù)組,但數(shù)組的數(shù)據(jù)類型是兩部分組成的[n]TYPE,這個整體才是數(shù)組的數(shù)據(jù)類型。所以,[4]int和[5]int是兩種不同的數(shù)組類型
var (
a1 [4]int
a2 [5]int
)
fmt.Println(reflect.TypeOf(a1))
fmt.Println(reflect.TypeOf(a2))
2.3 數(shù)組默認(rèn)值
當(dāng)一個變量被聲明之后, 都會立即賦予一個默認(rèn)值, 數(shù)組的默認(rèn)值和數(shù)組的數(shù)據(jù)類型有關(guān)
var a1 [5]int
fmt.Println(a1) // [0 0 0 0 0]
var a2 [4]string
fmt.Println(a2) // [ ]
2.4 聲明并初始化
如果不想填充默認(rèn)值, 可以聲明時就賦值
a1 := [3]int{1, 2, 3}
fmt.Println(a1)
// 如果將元素個數(shù)指定為特殊符號...,則表示通過初始化時的給定的值個數(shù)來推斷數(shù)組長度
a2 := [...]int{1, 2, 3, 4}
fmt.Println(a2)
a3 := [...]int{1, 1, 1}
fmt.Println(a3)
// 如果聲明數(shù)組時,只想給其中某幾個元素初始化賦值,則使用索引號
a4 := [4]int{0: 1, 3: 5}
fmt.Println(a4)
3、訪問與修改
可以通過數(shù)組的索引訪問數(shù)組的值
a := [4]int{0: 1, 2: 5}
fmt.Println(a[0])
fmt.Println(a[2])
同理可通過數(shù)組的索引修改數(shù)組的值
a[0] = 10
a[3] = 20
fmt.Println(a[0])
fmt.Println(a[3])
4、指針數(shù)組
可以聲明一個指針類型的數(shù)組,這樣數(shù)組中就可以存放指針。注意,指針的默認(rèn)初始化值為nil
例如,創(chuàng)建int類型指針的數(shù)組
a := [4]*int{0: new(int), 3: new(int)}
fmt.Println(a)
// [0xc00001c2a8 <nil> <nil> 0xc00001c2b0]
// 如果指針地址為空, 是會報空指針錯誤的, 比如
// *a[1] = 3
// panic: runtime error: invalid memory address or nil pointer dereference
*a[0] = 10
*a[3] = 20
fmt.Println(a)
fmt.Println(*a[0], *a[3])
// 為1賦值
a[1] = new(int)
*a[1] = 30
fmt.Println(a, *a[1])
5、數(shù)組拷貝
在Go中,由于數(shù)組算是一個值類型,所以可以將它賦值給其它數(shù)組
因為數(shù)組類型的完整定義為[n]TYPE,所以數(shù)組賦值給其它數(shù)組的時候,n和TYPE必須相同
修改 a2 數(shù)組元素的值,不會影響 a1 數(shù)組
例如:
a1 := [4]string{"a", "b", "c", "m"}
a2 := [4]string{"x", "y", "z", "n"}
a1 = a2
fmt.Println(a1, a2)
數(shù)組賦值給其它數(shù)組時,實際上是完整地拷貝一個數(shù)組。所以,如果數(shù)組是一個指針型的數(shù)組,那么拷貝的將是指針數(shù)組,而不會拷貝指針?biāo)赶虻膶ο?/p>
a1 := [4]*string{new(string), new(string), new(string), new(string)}
a2 := a1
fmt.Println(a1, a2)
*a1[0] = "A"
*a1[1] = "B"
*a1[2] = "C"
*a1[3] = "D"
fmt.Println(*a1[0], *a2[0])
// A A
6、數(shù)組遍歷
range關(guān)鍵字可以對array進行迭代,每次返回一個index和對應(yīng)的元素值。可以將range的迭代結(jié)合for循環(huán)對array進行遍歷
a := [4]int{1, 2, 3, 4}
for i, v := range a {
fmt.Println(i, v)
}
/*
0 1
1 2
2 3
3 4
*/
7、多維數(shù)組
可以通過組合兩個一維數(shù)組的方式構(gòu)成二維數(shù)組, 二維數(shù)據(jù)還是比較常用,
比如定義坐標(biāo), 表示4個坐標(biāo)(1,1) (2,2) (3,3) (4,4)
// pos := [4][2]int{{1, 1}, {2, 2}, {3, 3}, {4, 4}}
fmt.Println(pos)
// [[1 1] [2 2] [3 3] [4 4]]
// 修改第一點的坐標(biāo)
pos[0] = [2]int{10, 10}
fmt.Println(pos)
// [[10 10] [2 2] [3 3] [4 4]]
8、數(shù)組作為函數(shù)參數(shù)
Go中的傳值方式是按值傳遞,這意味著給變量賦值、給函數(shù)傳參時,都是直接拷貝一個副本然后將副本賦值給對方的。這樣的拷貝方式意味著:
如果數(shù)據(jù)結(jié)構(gòu)體積龐大,則要完整拷貝一個數(shù)據(jù)結(jié)構(gòu)副本時效率會很低 函數(shù)內(nèi)部修改數(shù)據(jù)結(jié)構(gòu)時,只能在函數(shù)內(nèi)部生效,函數(shù)一退出就失效了,因為它修改的是副本對象
示例
func TestMain1(t *testing.T) {
payload := [4]int{1}
fmt.Printf("%p\n", &payload) // 0xc00014a040
change(payload) // 0xc00014a060
}
func change(payload [4]int) {
fmt.Printf("%p\n", &payload)
payload[0] = 10
}
