欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

初探Golang數(shù)據(jù)結(jié)構(gòu)之Slice的使用

 更新時間:2023年09月18日 16:47:36   作者:freesia13279  
在學(xué)習(xí)Go語言時,一直對數(shù)組和切片的使用場景好奇,不明白為什么推薦使用切片來代替數(shù)組,所以本文就來和大家梳理一下Slice切片的相關(guān)知識吧

在閱讀Go語言圣經(jīng)時,一直對數(shù)組和切片的使用場景好奇,不明白為什么推薦使用切片來代替數(shù)組。希望能通過一些梳理,能更好的理解切片和數(shù)組,找到他們合適的使用場景。

切片與數(shù)組

關(guān)于切片和數(shù)組怎么選擇,我們來討論下這個問題。

在Go中,數(shù)組是值類型,賦值和函數(shù)傳參都會復(fù)制整個數(shù)組數(shù)據(jù)。

func main() {
    a := [2]int{100, 200}
    // 賦值
    var b = a
    fmt.Printf("a : %p , %v\n", &a, a)
    fmt.Printf("b : %p , %v\n", &b, b)
    // 函數(shù)傳參
    f(a)
    f(b)
}
func f(array [2]int) {
    fmt.Printf("array : %p , %v\n", &array, array)
}

輸出結(jié)果:

a : 0xc0000180a0 , [100 200]
b : 0xc0000180b0 , [100 200]
array : 0xc0000180f0 , [100 200]
array : 0xc000018110 , [100 200]

可以看到,四個內(nèi)存地址都不相同,印證了前面的說法。當數(shù)組數(shù)據(jù)量達到百萬級別時,復(fù)制數(shù)組會給內(nèi)存帶來巨大的壓力,那能否通過傳遞指針來解決呢?

func main() {
    a := [1]int{100}
    f1(&a)
    fmt.Printf("array : %p , %v\n", &a, a)
}
func f1(p *[1]int) {
    fmt.Printf("f1 array : %p , %v\n", p, *p)
    (*p)[0] += 100
}

輸出結(jié)果:

f1 array : 0xc0000b0008 , [100]
array : 0xc0000b0008 , [200]

可以看到,數(shù)組指針可以實現(xiàn)我們想要的效果,解決了復(fù)制數(shù)組帶來的內(nèi)存問題,不過函數(shù)接收的指針來自值拷貝,相對來說沒有切片那么靈活。

func main() {
    a := [1]int{100}
    f1(&a)
    // 切片
    b := a[:]
    f2(&b)
    fmt.Printf("array : %p , %v\n", &a, a)
}
func f1(p *[1]int) {
    fmt.Printf("f1 array : %p , %v\n", p, *p)
    (*p)[0] += 100
}
func f2(p *[]int) {
    fmt.Printf("f2 array : %p , %v\n", p, *p)
    (*p)[0] += 100
}
//輸出結(jié)果
f1 array : 0xc000018098 , [100]
f2 array : 0xc00000c030 , [200]
array : 0xc000018098 , [300]

可以看到,切片的指針和原來數(shù)組的指針是不同的。

總結(jié)

通常來說,使用數(shù)組進行參數(shù)傳遞會消耗較多內(nèi)存,采用切片可以避免此問題。切片是引用傳遞,不會占用較多內(nèi)存,效率更高一些。

切片的數(shù)據(jù)結(jié)構(gòu)

切片在編譯期是 cmd/compile/internal/types/type.go 包下的Slice類型,而它的運行時的數(shù)據(jù)結(jié)構(gòu)位于 reflect.SliceHeader

type SliceHeader struct {
        Data uintptr // 指向數(shù)組的指針
        Len  int    // 當前切片的長度
        Cap  int    // 當前切片的容量,cap 總是 >= len
}
// 占用24個字節(jié)
fmt.Println(unsafe.Sizeof(reflect.SliceHeader{}))

切片是對數(shù)組一個連續(xù)片段的引用,這個片段可以是整個數(shù)組,也可以是數(shù)組的一部分。切片的長度可以在運行時修改,最小為0,最大為關(guān)聯(lián)數(shù)組的長度,切片是一個長度可變的動態(tài)窗口。

創(chuàng)建切片

使用make

slice := make([]int, 4, 6)

內(nèi)存空間申請了6個int類型的內(nèi)存大小。由于len=4,所以后面2個空間暫時無法訪問到,但是容量是存在的。此時數(shù)組里每個變量都=0。

字面量

slice := []int{0, 1, 2}

nil切片和空切片

// nil 切片
var s []int
// 空切片 
s2 := make([]int, 0)
s3 := []int{}

空切片和 nil 切片的區(qū)別在于,空切片指向的地址不是nil,指向的是一個內(nèi)存地址,但是它沒有分配任何內(nèi)存空間,即底層元素包含0個元素。

func main() {
    var s []int
    s2 := []int{}
    s3 := make([]int, 0)
    fmt.Println(s == nil)
    fmt.Println(s2 == nil)
    fmt.Println(s3 == nil)
}
// 輸出結(jié)果
true
false
false

簡單說,nil切片指針值為nil;而空切片的指針值不為nil,

需要說明的一點是,不管是使用 nil 切片還是空切片,對其調(diào)用內(nèi)置函數(shù) append,len 和 cap 的效果都是一樣的。

但使用append時要注意:

  • 如果append追加的數(shù)據(jù)長度小于等于cap-len,只做一次數(shù)據(jù)拷貝。
  • 如果append追加的數(shù)據(jù)長度大于cap-len,則會分配一塊更大的內(nèi)存,然后把原數(shù)據(jù)拷貝過來,再進行追加。

特別當我們需要構(gòu)建一個切片,是從原有切片復(fù)制而來時,要注意值覆蓋問題。

func main() {
    s1 := []int{0, 1, 2, 3} // 先定義一個現(xiàn)有切片
    s2 := s1[0:1]           // 復(fù)制現(xiàn)有的切片
    s2 = append(s2, 100)
    fmt.Print(s1)
}

輸出結(jié)果

[0 100 2 3]

原因還是切片本質(zhì)上是數(shù)組的一個動態(tài)窗口,當cap夠用時,不會新開辟內(nèi)存空間進行復(fù)制,此時對數(shù)組的任何修改,都會對其他代理此數(shù)組的切片產(chǎn)生連帶影響。

到此這篇關(guān)于初探Golang數(shù)據(jù)結(jié)構(gòu)之Slice的使用的文章就介紹到這了,更多相關(guān)Go Slice內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言中嵌入C語言的方法

    Go語言中嵌入C語言的方法

    這篇文章主要介紹了Go語言中嵌入C語言的方法,實例分析了Go語言中cgo工具的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • Golang繼承模擬實例詳解

    Golang繼承模擬實例詳解

    這篇文章主要介紹了Golang繼承模擬方法,結(jié)合實例形式分析了Go語言實現(xiàn)繼承的原理與相關(guān)操作技巧,需要的朋友可以參考下
    2016-07-07
  • Go項目配置管理神器之viper的介紹與使用詳解

    Go項目配置管理神器之viper的介紹與使用詳解

    viper是一個完整的?Go應(yīng)用程序的配置解決方案,它被設(shè)計為在應(yīng)用程序中工作,并能處理所有類型的配置需求和格式,下面這篇文章主要給大家介紹了關(guān)于Go項目配置管理神器之viper的介紹與使用,需要的朋友可以參考下
    2023-02-02
  • go 類型轉(zhuǎn)換方式(interface 類型的轉(zhuǎn)換)

    go 類型轉(zhuǎn)換方式(interface 類型的轉(zhuǎn)換)

    這篇文章主要介紹了go 類型轉(zhuǎn)換方式(interface 類型的轉(zhuǎn)換),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go語言method詳解

    Go語言method詳解

    這篇文章主要介紹了Go語言method詳解,本文總結(jié)了在使用method的時候重要注意幾點、指針作為receiver、method繼承等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • Go文件操作(新建打開寫入讀取刪除關(guān)閉)學(xué)習(xí)筆記

    Go文件操作(新建打開寫入讀取刪除關(guān)閉)學(xué)習(xí)筆記

    這篇文章主要為大家介紹了Go文件操作(新建打開寫入讀取刪除關(guān)閉)學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • go編譯so庫讓python引用編譯后沒有.h文件的問題

    go編譯so庫讓python引用編譯后沒有.h文件的問題

    有時python需要引用go的一些開源庫,這時就需要go編譯成python可調(diào)用的庫,本文給大家介紹了go編譯so庫讓python引用,編譯后沒有.h文件的問題,需要的朋友可以參考下
    2024-02-02
  • Golang中channel使用的一些小技巧

    Golang中channel使用的一些小技巧

    這篇文章主要介紹了Golang中channel使用的一些小技巧,本文講解了關(guān)閉2次、讀取的時候channel提前關(guān)閉了、向已經(jīng)關(guān)閉的channel寫數(shù)據(jù)等技巧及這實例代碼,需要的朋友可以參考下
    2015-07-07
  • go語言更高精度的Sleep實例解析

    go語言更高精度的Sleep實例解析

    這篇文章主要為大家介紹了go語言更高精度的Sleep實例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • go語言實現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲的示例代碼

    go語言實現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲的示例代碼

    本文主要介紹了go語言實現(xiàn)并發(fā)網(wǎng)絡(luò)爬蟲的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03

最新評論