深入理解Go語言中的數(shù)組和切片
一、類型
數(shù)組是值類型,將一個(gè)數(shù)組賦值給另一個(gè)數(shù)組時(shí),傳遞的是一份拷貝。
切片是引用類型,切片包裝的數(shù)組稱為該切片的底層數(shù)組。
我們來看一段代碼
//a是一個(gè)數(shù)組,注意數(shù)組是一個(gè)固定長度的,初始化時(shí)候必須要指定長度,不指定長度的話就是切片了
a := [3]int{1, 2, 3}
//b是數(shù)組,是a的一份拷貝
b := a
//c是切片,是引用類型,底層數(shù)組是a
c := a[:]
for i := 0; i < len(a); i++ {
a[i] = a[i] + 1
}
//改變a的值后,b是a的拷貝,b不變,c是引用,c的值改變
fmt.Println(a) //[2,3,4]
fmt.Println(b) //[1 2 3]
fmt.Println(c) //[2,3,4]
二、make
make 只能用于slice, map 和 channel, 所以下面一段代碼生成了一個(gè)slice,是引用類型
s1 := make([]int, 0, 3)
for i := 0; i < cap(s1); i++ {
s1 = append(s1, i)
}
s2 := s1
for i := 0; i < len(a); i++ {
s1[i] = s1[i] + 1
}
fmt.Println(s1) //[1 2 3]
fmt.Println(s2) //[1 2 3]
三、當(dāng)對(duì)slice append 超出底層數(shù)組的界限時(shí)
//n1是n2的底層數(shù)組
n1 := [3]int{1, 2, 3}
n2 := n1[0:3]
fmt.Println("address of items in n1: ")
for i := 0; i < len(n1); i++ {
fmt.Printf("%p\n", &n1[i])
}
//address of items in n1:
//0xc20801e160
//0xc20801e168
//0xc20801e170
fmt.Println("address of items in n2: ")
for i := 0; i < len(n2); i++ {
fmt.Printf("%p\n", &n2[i])
}
//address of items in n2:
//0xc20801e160
//0xc20801e168
//0xc20801e170
//對(duì)n2執(zhí)行append操作后,n2超出了底層數(shù)組n1的j
n2 = append(n2, 1)
fmt.Println("address of items in n1: ")
for i := 0; i < len(n1); i++ {
fmt.Printf("%p\n", &n1[i])
}
//address of items in n1:
//0xc20801e160
//0xc20801e168
//0xc20801e170
fmt.Println("address of items in n2: ")
for i := 0; i < len(n2); i++ {
fmt.Printf("%p\n", &n2[i])
}
//address of items in n2:
//0xc20803a2d0
//0xc20803a2d8
//0xc20803a2e0
//0xc20803a2e8
四、引用“失效”
實(shí)現(xiàn)了刪除slice最后一個(gè)item的函數(shù)
func rmLast(a []int) {
fmt.Printf("[rmlast] the address of a is %p", a)
a = a[:len(a)-1]
fmt.Printf("[rmlast] after remove, the address of a is %p", a)
}
調(diào)用此函數(shù)后,發(fā)現(xiàn)原來的slice并沒有改變
func main() {
xyz := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("[main] the address of xyz is %p\n", xyz)
rmLast(xyz)
fmt.Printf("[main] after remove, the address of xyz is %p\n", xyz)
fmt.Printf("%v", xyz) //[1 2 3 4 5 6 7 8 9]
}
打印出來的結(jié)果如下:
[main] the address of xyz is 0xc2080365f0 [rmlast] the address of a is 0xc2080365f0 [rmlast] after remove, the address of a is 0xc2080365f0 [main] after remove, the address of xyz is 0xc2080365f0 [1 2 3 4 5 6 7 8 9]
這里直接打印了slice的指針值,因?yàn)?code>slice是引用類型,所以指針值都是相同的,我們換成打印slice的地址看下
func rmLast(a []int) {
fmt.Printf("[rmlast] the address of a is %p", &a)
a = a[:len(a)-1]
fmt.Printf("[rmlast] after remove, the address of a is %p", &a)
}
func main() {
xyz := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Printf("[main] the address of xyz is %p\n", &xyz)
rmLast(xyz)
fmt.Printf("[main] after remove, the address of xyz is %p\n", &xyz)
fmt.Printf("%v", xyz) //[1 2 3 4 5 6 7 8 9]
}
結(jié)果:
[main] the address of xyz is 0xc20801e1e0 [rmlast] the address of a is 0xc20801e200 [rmlast] after remove, the address of a is 0xc20801e200 [main] after remove, the address of xyz is 0xc20801e1e0 [1 2 3 4 5 6 7 8 9]
這次可以看到slice作為函數(shù)參數(shù)傳入函數(shù)時(shí),實(shí)際上也是拷貝了一份slice,因?yàn)?code>slice本身是個(gè)指針,所以從現(xiàn)象來看,slice是引用類型
總結(jié)
以上就是這篇文章的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)或者工作帶來一定的幫助,如果有疑問大家可以留言交流。
相關(guān)文章
Golang cron 定時(shí)器和定時(shí)任務(wù)的使用場景
Ticker是一個(gè)周期觸發(fā)定時(shí)的計(jì)時(shí)器,它會(huì)按照一個(gè)時(shí)間間隔往channel發(fā)送系統(tǒng)當(dāng)前時(shí)間,而channel的接收者可以以固定的時(shí)間間隔從channel中讀取事件,這篇文章主要介紹了Golang cron 定時(shí)器和定時(shí)任務(wù),需要的朋友可以參考下2022-09-09
Go存儲(chǔ)基礎(chǔ)使用direct io方法實(shí)例
這篇文章主要介紹了Go存儲(chǔ)基礎(chǔ)之如何使用direct io方法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Go并發(fā)原語之SingleFlight請(qǐng)求合并方法實(shí)例
本文我們來學(xué)習(xí)一下 Go 語言的擴(kuò)展并發(fā)原語:SingleFlight,SingleFlight 的作用是將并發(fā)請(qǐng)求合并成一個(gè)請(qǐng)求,以減少重復(fù)的進(jìn)程來優(yōu)化 Go 代碼2023-12-12
Golang使用CopyIn進(jìn)行批量創(chuàng)建的示例代碼
本文主要介紹了Golang使用CopyIn進(jìn)行批量創(chuàng)建的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07

