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

Go語言中一定要知道的切片使用注意事項(xiàng)總結(jié)

 更新時(shí)間:2023年06月12日 09:25:42   作者:starrySky  
了解和掌握切片的使用注意事項(xiàng),可以避免意外的程序行為,所以本文就來和大家深入探討一下Go語言切片常見的注意事項(xiàng),希望對大家有所幫助

1. 引言

在之前我寫了一篇 切片比數(shù)組好用在哪 的文章,仔細(xì)介紹了切片相比于數(shù)組的優(yōu)點(diǎn)。但切片事實(shí)上也隱藏著一些潛在的陷阱和需要注意的細(xì)節(jié),了解和掌握切片的使用注意事項(xiàng),可以避免意外的程序行為。本文將深入探討Go語言切片常見的注意事項(xiàng),從而能夠更好得使用切片。

2. 注意事項(xiàng)

2.1 注意一個(gè)數(shù)組可以同時(shí)被多個(gè)切片引用

當(dāng)創(chuàng)建一個(gè)切片時(shí),它實(shí)際上是對一個(gè)底層數(shù)組的引用。這意味著對切片的修改會直接影響到底層數(shù)組以及其他引用該數(shù)組的切片。這種引用關(guān)系可能導(dǎo)致一些意想不到的結(jié)果,下面是一個(gè)示例代碼來說明這個(gè)問題:

package main
import "fmt"
func main() {
        array := [5]int{1, 2, 3, 4, 5}
        firstSlice := array[1:4] // 創(chuàng)建一個(gè)切片,引用了底層數(shù)組的索引1到3的元素
        secondSlice := array[1:3]
        fmt.Println("Original array:", firstSlice)  // 輸出第一個(gè)切片 [2 3 4]
        fmt.Println("Original slice:", secondSlice) // 輸出第二個(gè)切片 [2 3]
        // 修改切片的第一個(gè)元素
        firstSlice[0] = 10
        fmt.Println("Modified array:", firstSlice)  // 輸出第一個(gè)切片 [10 3 4]
        fmt.Println("Modified slice:", secondSlice) // 輸出第二個(gè)切片 [10 3]
}

在上述代碼中,我們創(chuàng)建了一個(gè)長度為5的數(shù)組array和兩個(gè)引用該數(shù)組的切片firstSlicesecondSlice。當(dāng)我們修改第一個(gè)切片的第一個(gè)元素為10時(shí),底層數(shù)組的對應(yīng)位置的元素也被修改了。這里導(dǎo)致了數(shù)組和其他引用該數(shù)組的切片的內(nèi)容也會受到影響。

如果我們有多個(gè)切片同時(shí)引用了同一個(gè)底層數(shù)組,同時(shí)我們并不想由于對某個(gè)切片的修改,影響到另外一個(gè)切片的數(shù)據(jù),此時(shí)我們可以新創(chuàng)建一個(gè)切片,使用內(nèi)置的copy函數(shù)來復(fù)制原切片元素的值。示例代碼如下:

package main
import "fmt"
func main() {
        array := [5]int{1, 2, 3, 4, 5}
        slice := array[1:4]
        // 復(fù)制切片創(chuàng)建一個(gè)獨(dú)立的底層數(shù)組
        newSlice := make([]int, len(slice))
        copy(newSlice, slice)
        fmt.Println("Original array:", array) // 輸出原始數(shù)組 [1 2 3 4 5]
        fmt.Println("Original slice:", slice) // 輸出初始切片 [2 3 4]
        fmt.Println("New slice:", newSlice)  // 輸出新創(chuàng)建的切片 [2 3 4]
        // 修改newSlice的第一個(gè)元素
        newSlice[0] = 10
        fmt.Println("Modified array:", array)// 輸出修改后的數(shù)組 [1 2 3 4 5]
        fmt.Println("Original slice:", slice)// 輸出初始切片 [2 3 4]
        fmt.Println("New slice:", newSlice)// 輸出修改后的切片 [10 3 4]
}

通過創(chuàng)建了一個(gè)新的切片newSlice,它擁有獨(dú)立的底層數(shù)組,同時(shí)使用copy函數(shù)復(fù)制原切片的值,我們現(xiàn)在修改newSlice不會影響原始數(shù)組或原始切片。

2.2 注意自動(dòng)擴(kuò)容可能帶來的性能問題

在Go語言中,切片的容量是指底層數(shù)組的大小,而長度是切片當(dāng)前包含的元素?cái)?shù)量。當(dāng)切片的長度超過容量時(shí),Go語言會自動(dòng)擴(kuò)容切片。擴(kuò)容操作涉及到重新分配底層數(shù)組,并將原有數(shù)據(jù)復(fù)制到新的數(shù)組中。下面先通過一個(gè)示例代碼,演示切片的自動(dòng)擴(kuò)容機(jī)制:

package main
import "fmt"
func main() {
        slice := make([]int, 3, 5) // 創(chuàng)建一個(gè)初始長度為3,容量為5的切片
        fmt.Println("Initial slice:", slice)        // 輸出初始切片 [0 0 0]
        fmt.Println("Length:", len(slice))          // 輸出切片長度 3
        fmt.Println("Capacity:", cap(slice))        // 輸出切片容量 5
        slice = append(slice, 1, 2, 3)              // 添加3個(gè)元素到切片,長度超過容量
        fmt.Println("After appending:", slice)      // 輸出擴(kuò)容后的切片 [0 0 0 1 2 3]
        fmt.Println("Length:", len(slice))          // 輸出切片長度 6
        fmt.Println("Capacity:", cap(slice))        // 輸出切片容量 10
}

在上述代碼中,我們使用make函數(shù)創(chuàng)建了一個(gè)初始長度為3,容量為5的切片slice。然后,我們通過append函數(shù)添加了3個(gè)元素到切片,導(dǎo)致切片的長度超過了容量。此時(shí),Go語言會自動(dòng)擴(kuò)容切片,創(chuàng)建一個(gè)新的底層數(shù)組,并將原有數(shù)據(jù)復(fù)制到新的數(shù)組中。最終,切片的長度變?yōu)?,容量變?yōu)?0。

但是切片的自動(dòng)擴(kuò)容機(jī)制,其實(shí)是存在性能開銷的,需要?jiǎng)?chuàng)建一個(gè)新的數(shù)組,同時(shí)將數(shù)據(jù)全部拷貝到新數(shù)組中,切片再引用新的數(shù)組。下面先通過基準(zhǔn)測試,展示沒有設(shè)置初始容量和設(shè)置了初始容量兩種情況下的性能差距:

package main
import (
        "fmt"
        "testing"
)
func BenchmarkSliceAppendNoCapacity(b *testing.B) {
        for i := 0; i < b.N; i++ {
                var slice []int
                for j := 0; j < 1000; j++ {
                        slice = append(slice, j)
                }
        }
}
func BenchmarkSliceAppendWithCapacity(b *testing.B) {
        for i := 0; i < b.N; i++ {
                slice := make([]int, 0, 1000)
                for j := 0; j < 1000; j++ {
                        slice = append(slice, j)
                }
        }
}

在上述代碼中,我們定義了兩個(gè)基準(zhǔn)測試函數(shù):BenchmarkSliceAppendNoCapacityBenchmarkSliceAppendWithCapacity。其中,BenchmarkSliceAppendNoCapacity測試了在沒有設(shè)置初始容量的情況下,循環(huán)追加元素到切片的性能;BenchmarkSliceAppendWithCapacity測試了在設(shè)置了初始容量的情況下,循環(huán)追加元素到切片的性能。基準(zhǔn)測試結(jié)果如下:

BenchmarkSliceAppendNoCapacity-4          280983              4153 ns/op           25208 B/op         12 allocs/op
BenchmarkSliceAppendWithCapacity-4       1621177              712.2 ns/op              0 B/op          0 allocs/op

其中ns/op 表示每次操作的平均執(zhí)行時(shí)間,即函數(shù)執(zhí)行的耗時(shí)。B/op 表示每次操作的平均內(nèi)存分配量,即每次操作分配的內(nèi)存大小。allocs/op 表示每次操作的平均內(nèi)存分配次數(shù)。

可以看到,在設(shè)置了初始容量的情況下,性能要明顯優(yōu)于沒有設(shè)置初始容量的情況。循環(huán)追加1000個(gè)元素到切片時(shí),設(shè)置了初始容量的情況下平均每次操作耗時(shí)約為712.2納秒,而沒有設(shè)置初始容量的情況下平均每次操作耗時(shí)約為4153 納秒。這是因?yàn)樵O(shè)置了初始容量避免了頻繁的擴(kuò)容操作,提高了性能。

所以,雖然切片的自動(dòng)擴(kuò)容好用,但是其也是存在代價(jià)的。更好得使用切片,應(yīng)該避免頻繁的擴(kuò)容操作,這里可以在創(chuàng)建切片時(shí)預(yù)估所需的容量,并提前指定切片的容量,這樣可以減少擴(kuò)容次數(shù),提高性能。需要注意的是,如果你不知道切片需要多大的容量,可以使用適當(dāng)?shù)某跏既萘?,然后根?jù)需要?jiǎng)討B(tài)擴(kuò)容。

2.3 注意切片參數(shù)修改原始數(shù)據(jù)的陷阱

在Go語言中,切片是引用類型。當(dāng)將切片作為參數(shù)傳遞給函數(shù)時(shí),實(shí)際上是傳遞了底層數(shù)組的引用。這意味著在函數(shù)內(nèi)部修改切片的元素會影響到原始切片。下面是一個(gè)示例代碼來說明這個(gè)問題:

package main

import "fmt"

func modifySlice(slice []int) {
     slice[0] = 10
     fmt.Println("Modified slice inside function:", slice)
}

func main() {
     originalSlice := []int{1, 2, 3}
     fmt.Println("Original slice:", originalSlice)
     modifySlice(originalSlice)
     fmt.Println("Original slice after function call:", originalSlice)
}

在上述代碼中,我們定義了一個(gè)modifySlice函數(shù),它接收一個(gè)切片作為參數(shù),并在函數(shù)內(nèi)部修改了切片的第一個(gè)元素,并追加了一個(gè)新元素。然后,在main函數(shù)中,我們創(chuàng)建了一個(gè)初始切片originalSlice,并將其作為參數(shù)傳遞給modifySlice函數(shù)。當(dāng)我們運(yùn)行代碼時(shí),輸出如下:

Original slice: [1 2 3]
Modified slice inside function: [10 2 3]
Original slice after function call: [10 2 3]

可以看到,在modifySlice函數(shù)內(nèi)部,我們修改了切片的第一個(gè)元素并追加了一個(gè)新元素。這導(dǎo)致了函數(shù)內(nèi)部切片的變化。然而,當(dāng)函數(shù)返回后,原始切片originalSlice數(shù)據(jù)也受到影響。

如果我們希望函數(shù)內(nèi)部的修改不影響原始切片,可以通過復(fù)制切片來解決。修改示例代碼如下:

package main
import "fmt"
func modifySlice(slice []int) {
        newSlice := make([]int, len(slice))
        copy(newSlice, slice)
        newSlice[0] = 10
        fmt.Println("Modified slice inside function:", newSlice)
}
func main() {
        originalSlice := []int{1, 2, 3}
        fmt.Println("Original slice:", originalSlice)
        modifySlice(originalSlice)
        fmt.Println("Original slice after function call:", originalSlice)
}

通過使用make函數(shù)創(chuàng)建一個(gè)新的切片newSlice,并使用copy函數(shù)將原始切片復(fù)制到新切片中,我們確保了函數(shù)內(nèi)部操作的是新切片的副本。這樣,在修改新切片時(shí)不會影響原始切片的值。當(dāng)我們運(yùn)行修改后的代碼時(shí),輸出如下:

Original slice: [1 2 3]
Modified slice inside function: [10 2 3]
Original slice after function call: [1 2 3]

可以看到,原始切片保持了不變,函數(shù)內(nèi)部的修改只影響了復(fù)制的切片。這樣我們可以避免在函數(shù)間傳遞切片時(shí)對原始切片造成意外修改。

3. 總結(jié)

本文深入探討了Go語言切片的一些注意事項(xiàng),旨在幫助讀者更好地使用切片。

首先,切片是對底層數(shù)組的引用。修改切片的元素會直接影響到底層數(shù)組以及其他引用該數(shù)組的切片。如果需要避免修改一個(gè)切片影響其他切片或底層數(shù)組,可以使用copy函數(shù)創(chuàng)建一個(gè)獨(dú)立的底層數(shù)組。

其次,切片的自動(dòng)擴(kuò)容可能帶來性能問題。當(dāng)切片的長度超過容量時(shí),Go語言會自動(dòng)擴(kuò)容切片,需要重新分配底層數(shù)組并復(fù)制數(shù)據(jù)。為了避免頻繁的擴(kuò)容操作,可以在創(chuàng)建切片時(shí)預(yù)估所需的容量,并提前指定切片的容量。

最后,需要注意切片作為參數(shù)傳遞給函數(shù)時(shí),函數(shù)內(nèi)部的修改會影響到原始切片。如果希望函數(shù)內(nèi)部的修改不影響原始切片,可以通過復(fù)制切片來解決。

了解和掌握這些切片的注意事項(xiàng)和技巧,可以避免意外的程序行為。

到此這篇關(guān)于Go語言中一定要知道的切片使用注意事項(xiàng)總結(jié)的文章就介紹到這了,更多相關(guān)Go語言切片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang接口的正確用法分享

    golang接口的正確用法分享

    這篇文章主要介紹了golang接口的正確用法分享的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • 淺談golang fasthttp踩坑經(jīng)驗(yàn)

    淺談golang fasthttp踩坑經(jīng)驗(yàn)

    本文主要介紹了golang fasthttp踩坑經(jīng)驗(yàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Go語言如何利用Mutex保障數(shù)據(jù)讀寫正確

    Go語言如何利用Mutex保障數(shù)據(jù)讀寫正確

    這篇文章主要介紹了互斥鎖的實(shí)現(xiàn)機(jī)制,以及?Go?標(biāo)準(zhǔn)庫的互斥鎖?Mutex?的基本使用方法,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考一下
    2023-05-05
  • GO語言實(shí)現(xiàn)簡單的目錄復(fù)制功能

    GO語言實(shí)現(xiàn)簡單的目錄復(fù)制功能

    這篇文章主要介紹了GO語言實(shí)現(xiàn)簡單的目錄復(fù)制功能,通過新建及復(fù)制內(nèi)容等操作最終實(shí)現(xiàn)復(fù)制目錄的功能效果,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • 深入解析Go語言中crypto/subtle加密庫

    深入解析Go語言中crypto/subtle加密庫

    本文主要介紹了深入解析Go語言中crypto/subtle加密庫,詳細(xì)介紹crypto/subtle加密庫主要函數(shù)的用途、工作原理及實(shí)際應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Golang判斷兩個(gè)鏈表是否相交的方法詳解

    Golang判斷兩個(gè)鏈表是否相交的方法詳解

    這篇文章主要為大家詳細(xì)介紹了如何通過Golang判斷兩個(gè)鏈表是否相交,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • Golang實(shí)現(xiàn)延遲調(diào)用的項(xiàng)目實(shí)踐

    Golang實(shí)現(xiàn)延遲調(diào)用的項(xiàng)目實(shí)踐

    本文主要介紹了Golang實(shí)現(xiàn)延遲調(diào)用的項(xiàng)目實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用

    GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用

    本文主要介紹了GO語言不固定參數(shù)函數(shù)與匿名函數(shù)的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 詳解go 動(dòng)態(tài)數(shù)組 二維動(dòng)態(tài)數(shù)組

    詳解go 動(dòng)態(tài)數(shù)組 二維動(dòng)態(tài)數(shù)組

    這篇文章主要介紹了go 動(dòng)態(tài)數(shù)組 二維動(dòng)態(tài)數(shù)組,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 一文教你學(xué)會Go中singleflight的使用

    一文教你學(xué)會Go中singleflight的使用

    緩存在項(xiàng)目中使用應(yīng)該是非常頻繁的,提到緩存只要了解過?singleflight?,基本都會用于緩存實(shí)現(xiàn)的一部分吧,下面就跟隨小編一起來學(xué)習(xí)一下singleflight的使用吧
    2024-02-02

最新評論