最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言中Slice常見陷阱與避免方法詳解

 更新時間:2023年02月14日 08:39:38   作者:陳明勇  
這篇文章主要為大家詳細(xì)介紹的是 Go 語言中的 Slice 的常見陷阱以及如何避免這些錯誤,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下

前言

Go 語言提供了很多方便的數(shù)據(jù)類型,其中包括 slice。然而,由于 slice 的特殊性質(zhì),在使用過程中易犯一些錯誤,如果不注意,可能導(dǎo)致程序出現(xiàn)意外行為。本文將詳細(xì)介紹 使用 slice 時易犯的一些錯誤,幫助讀者更好的使用 Goslice,避免犯錯誤。

slice 作為函數(shù) / 方法的參數(shù)進(jìn)行傳遞的陷阱

slice 作為參數(shù)進(jìn)行傳遞,有一些地方需要注意,先說結(jié)論:

1、在函數(shù)里修改切片元素的值,原切片的值也會被改變;

若想修改新切片的值,而不影響原切片的值,可以對原切片進(jìn)行深拷貝:

通過 copy(dst, src []Type) int 函數(shù)將原切片的元素拷貝到新切片中:此函數(shù)在拷貝時,會基于兩個切片中,最小長度為基礎(chǔ)去拷貝,也就是初始化新切片時,長度必須大于等于原切片的長度。

2、在函數(shù)里通過 append 方法,對切片執(zhí)行追加元素的操作,可能會引起切片擴(kuò)容,導(dǎo)致內(nèi)存分配的問題,可能會對程序的性能 造成影響;

為避免切片擴(kuò)容,導(dǎo)致內(nèi)存分配,對程序的性能造成影響,在初始化切片時,應(yīng)該根據(jù)使用場景,指定一個合理 cap 參數(shù)。

3、在函數(shù)里通過 append 函數(shù),對切片執(zhí)行追加元素的操作,原切片里不存在新元素。

若想實現(xiàn)執(zhí)行 append 函數(shù)之后,原切片也能得到新元素;需將函數(shù)的參數(shù)類型由 切片類型 改成 切片指針類型

通過例子來感受一下上面結(jié)論的由來:

package main

import "fmt"

func main() {
   s := []int{0, 2, 3}
   fmt.Printf("切片的長度:%d, 切片的容量:%d, 切片的元素:%v\n", len(s), cap(s), s) // 3 3 [0, 2, 3]
   sliceOperation(s)
   fmt.Printf("切片的長度:%d, 切片的容量:%d, 切片的元素:%v\n", len(s), cap(s), s) // 3 3 [1, 2, 3]
}

func sliceOperation(s []int) {
   s[0] = 1
   s = append(s, 4)
   fmt.Printf("切片的長度:%d, 切片的容量:%d, 切片的元素:%v\n", len(s), cap(s), s) // 4 6 [1, 2, 3]
}

首先定義并初始化切片 s,切片里有三個元素;

調(diào)用 sliceOperation 函數(shù),將切片作為參數(shù)進(jìn)行傳遞;

在函數(shù)里修改切片的第一個元素的值為 1,然后通過 append 函數(shù)插入元素 4,此時函數(shù)里的切片 由于容量不夠,s 的容量被擴(kuò)大了,變成 原 cap * 2 = 3 * 2 = 6;

打印結(jié)果已注釋在代碼里,通過打印結(jié)果可知:

  • 在函數(shù)里修改切片的第一個元素的值,原切片元素的值也會改變;
  • 在函數(shù)里通過 append 函數(shù),向切片追加元素 4,原切片并沒有此元素;
  • 函數(shù)里的切片擴(kuò)容了,原切片卻沒有。

由于切片是引用類型,因此在函數(shù)修改切片元素的值,原切片的元素值也會改變。

有的人可能會產(chǎn)生以下兩個疑問

1、既然切片是引用類型,為什么通過 append 追加元素,原切片 s 卻沒有新元素?

2、為什么函數(shù)里的切片擴(kuò)容了,原切片卻沒有?

在探究這兩個問題之前,我們需要了解切片的數(shù)據(jù)結(jié)構(gòu):

type slice struct {
   array unsafe.Pointer
   len   int
   cap   int
}

切片包含三個字段:array (指針類型,指向一個數(shù)組)、len (切片的長度)、cap (切片的容量)。

知道了切片的數(shù)據(jù)結(jié)構(gòu),我們通過圖片來直觀地看看切片 s

切片 s 沒有被修改之前,在內(nèi)存中是以上圖所描述的形式存在,array 指針變量指向數(shù)組 [0, 2, 3],長度為 3,容量為 3。

在執(zhí)行 sliceOperation 函數(shù)之后,原切片 ssliceOperation 函數(shù)里的切片 s 如上圖所示。

通過上上圖和上圖對比可知,底層數(shù)組 [0, 2, 3] 的第一個元素的值被修改為 1,然后追加元素 4,此時函數(shù)里的切片發(fā)生變化,長度 3 → 4,容量 3 → 6 變成原來的兩倍,底層數(shù)組的長度也由 3 → 6。

由于原切片s的長度為3,array 指針?biāo)赶虻膮^(qū)域只有 [1, 2, 3],這也是為什么在函數(shù)里新增了 元素 4,在原切片 s 里看不到的原因。

第一個問題解決了,我們來思考第二個問題的原因:

Go 中,函數(shù) / 方法的參數(shù)傳遞方式為值傳遞,main 函數(shù)將 s 傳遞過來,sliceOperation 函數(shù)用 s 去接收,此時的s為新的切片,只不過它們所指向的底層數(shù)組為同一個,長度和容量也是一樣。而擴(kuò)容操作是在新切片上進(jìn)行的,因此原切片不受影響。

slice 通過 make 函數(shù)初始化,后續(xù)操作不當(dāng)所造成的陷阱

使用 make 函數(shù)初始化切片后,如果在后續(xù)操作中沒有正確處理切片長度,容易造成以下陷阱:

越界訪問:如果訪問超出切片實際長度的索引,則會導(dǎo)致 index out of range 錯誤,例如:

func main() {
   s := make([]int, 0, 4)
   s[0] = 1 // panic: runtime error: index out of range [0] with length 0
}

通過 make([]int, 0, 4) 初始化切片,雖說容量為 4,但是長度為 0,如果通過索引去賦值,會發(fā)生panic;為避免 panic,可以通過 s := make([]int, 4)s := make([]int, 4, 4) 對切片進(jìn)行初始化。

切片初始化不當(dāng),通過 append 函數(shù)追加新元素的位置可能于預(yù)料之外

func main() {
   s := make([]int, 4)
   s = append(s, 1)
   fmt.Println(s[0]) // 0

   s2 := make([]int, 0, 4)
   s2 = append(s2, 1)
   fmt.Println(s2[0]) // 1
}

通過打印結(jié)果可知,對于切片 s,元素 1 沒有被放置在第一個位置,而對于切片 s2,元素 1 被放置在切片的第一個位置。這是因為通過 make([]int, 4)make([]int, 0, 4) 初始化切片,底層所指向的數(shù)組的值是不一樣的:

  • 第一種初始化的方式,切片的長度和容量都為 4,底層所指向的數(shù)組長度也是 4,數(shù)組的值為 [0, 0, 0, 0],每個位置的元素被賦值為零值,s = append(s, 1) 執(zhí)行后,s 切片的值為 [0, 0, 0, 0, 1];
  • 第二種初始化的方式,切片的長度為 0,容量為 4,底層所指向的數(shù)組長度為 0,數(shù)組的值為 [],s2 = append(s2, 1) 執(zhí)行后,s2 切片的值為 [1];
  • 通過 append 向切片追加元素,會執(zhí)行尾插操作。如果我們需要初始化一個空切片,然后從第一個位置開始插入元素,需要避免 make([]int, 4) 這種初始化的方式,否則添加的結(jié)果會在預(yù)料之外。

性能陷阱

內(nèi)存泄露

內(nèi)存泄露是指程序分配內(nèi)存后不再使用該內(nèi)存,但未將其釋放,導(dǎo)致內(nèi)存資源被浪費。

切片引用切片場景:如果一個切片有大量的元素,而它只有少部分元素被引用,其他元素存在于內(nèi)存中,但是沒有被使用,則會造成內(nèi)存泄露。代碼示例如下:

  var s []int

  func main() {
     sliceOperation()
     fmt.Println(s)
  }

  func sliceOperation() {
     a := make([]int, 0, 10)
     a = append(a, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
     s = a[0:4]
  }

上述代碼中,切片 a 的元素有 10 個,而切片 s 是基于 a 創(chuàng)建的,它底層所指向的數(shù)組與 a 所指向的數(shù)組是同一個,只不過范圍為前四個元素,而后六個元素依然存在于內(nèi)存中,卻沒有被使用,這樣會造成內(nèi)存泄露。為了避免內(nèi)存泄露,我們可以對代碼進(jìn)行改造: s = a[0:4]s = append(s, a[0:4]...),通過 append 進(jìn)行元素追加,這樣切片 a 底層的數(shù)組沒有被引用,后面會被 gc。

擴(kuò)容

擴(kuò)容陷阱在前面的例子也提到過,通過 append 方法,對切片執(zhí)行追加元素的操作,可能會引起切片擴(kuò)容,導(dǎo)致內(nèi)存分配的問題。

  func main() {
     s := make([]int, 0, 4)
     fmt.Printf("切片的長度:%d, 切片的容量:%d\n", len(s), cap(s)) // 4 4
     s = append(s, 1, 2, 3, 4, 5)
     fmt.Printf("切片的長度:%d, 切片的容量:%d\n", len(s), cap(s)) // 5 8
  }

切片擴(kuò)容,可能會對程序的性能 造成影響;為避免此情況的發(fā)生,應(yīng)該根據(jù)使用場景,估算切片的容量,指定一個合理 cap 參數(shù)。

到此這篇關(guān)于Go語言中Slice常見陷阱與避免方法詳解的文章就介紹到這了,更多相關(guān)Go語言Slice內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用?pprof?進(jìn)行性能分析的方法詳解

    使用?pprof?進(jìn)行性能分析的方法詳解

    pprof?是?Go?語言中用于性能分析的一個強(qiáng)大工具,它可以幫助開發(fā)人員找到應(yīng)用程序中的性能瓶頸,并提供詳細(xì)的分析報告,本文將介紹如何使用?pprof?進(jìn)行性能分析,需要的朋友可以參考下
    2023-05-05
  • 通過client-go來操作K8S集群的操作方法

    通過client-go來操作K8S集群的操作方法

    本文詳細(xì)介紹了client-go的安裝、配置和使用方法,并通過示例代碼展示了如何進(jìn)行常見的Kubernetes操作,希望這些內(nèi)容能幫助大家更好地理解和使用client-go,從而提高你的Kubernetes開發(fā)效率,感興趣的朋友一起看看吧
    2024-11-11
  • GO語言延遲函數(shù)defer用法詳解

    GO語言延遲函數(shù)defer用法詳解

    本文主要介紹了GO語言延遲函數(shù)defer用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • go語言題解LeetCode989數(shù)組形式的整數(shù)加法

    go語言題解LeetCode989數(shù)組形式的整數(shù)加法

    這篇文章主要為大家介紹了go語言題解LeetCode989數(shù)組形式的整數(shù)加法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Go語言中嵌入式緩存庫的用法詳解

    Go語言中嵌入式緩存庫的用法詳解

    Go?語言中有一些非常高效的嵌入式緩存庫,groupcache?和?bigcache?是兩個非常流行且高性能的庫,本文將詳細(xì)介紹一下二者的用法,有需要的小伙伴可以參考下
    2025-01-01
  • Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例

    Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例

    這篇文章主要為大家介紹了Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • golang標(biāo)準(zhǔn)庫time時間包的使用

    golang標(biāo)準(zhǔn)庫time時間包的使用

    時間和日期是我們編程中經(jīng)常會用到的,本文主要介紹了golang標(biāo)準(zhǔn)庫time時間包的使用,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • 使用Go+GoQuery庫實現(xiàn)頭條新聞采集

    使用Go+GoQuery庫實現(xiàn)頭條新聞采集

    在本文中,我們將介紹如何使用Go語言和GoQuery庫實現(xiàn)一個簡單的爬蟲程序,用于抓取頭條新聞的網(wǎng)頁內(nèi)容,我們還將使用爬蟲代理服務(wù),提高爬蟲程序的性能和安全性,我們將使用多線程技術(shù),提高采集效率,最后,我們將展示爬蟲程序的運行結(jié)果和代碼,需要的朋友可以參考下
    2023-10-10
  • 詳解Go中g(shù)in框架如何實現(xiàn)帶顏色日志

    詳解Go中g(shù)in框架如何實現(xiàn)帶顏色日志

    當(dāng)我們在終端上(比如Goland)運行g(shù)in框架搭建的服務(wù)時,會發(fā)現(xiàn)輸出的日志是可以帶顏色的,那這是如何實現(xiàn)的呢?本文就來和大家簡單講講
    2023-04-04
  • 利用Go語言追加內(nèi)容到文件末尾

    利用Go語言追加內(nèi)容到文件末尾

    關(guān)于Go語言讀寫文件,網(wǎng)上很多教程了,但是今天有個需求,想要把內(nèi)容追加寫到文件末尾,在網(wǎng)上找了很久才找到答案,現(xiàn)在分享給大家,有需要的可以參考借鑒。
    2016-09-09

最新評論

四子王旗| 梨树县| 彩票| 天全县| 九龙城区| 卢龙县| 崇明县| 泰州市| 德安县| 泗洪县| 凤山市| 甘德县| 桂林市| 贵港市| 江西省| 绩溪县| 文成县| 民乐县| 稻城县| 南京市| 砚山县| 九江市| 陵水| 汕头市| 安福县| 闽侯县| 虎林市| 合水县| 义马市| 宁河县| 周宁县| 甘孜县| 丹东市| 固始县| 澄城县| 翁牛特旗| 礼泉县| 保德县| 文成县| 鄢陵县| 瑞丽市|