1. 程式人生 > >Golang:slice之append時原陣列發生變化的問題

Golang:slice之append時原陣列發生變化的問題

使用append可以在slice之後追求元素,例如

nums:=[]int{1,2,3}
result:=append(nums,4)
fmt.Println(result)

這段程式碼很簡單,輸出result的值為:[1 2 3 4]
問題在於,進行這種操作時,原來的slice(即nums)所基於的陣列的值會不會發生變化呢?在Golang中,如果有多個slice基於了同一個陣列,則這些slice的資料是共享的(而不是每個slice複製一份)。也就說,如果改變了陣列的內容,則基於它的所有slice的值都會變化這段程式碼中nums的值沒有變化,但是並非所有時候都是如此。

回答這個問題,首先需要了解append函式實現原理:
1. 如果nums的cap夠用,則會直接在nums指向的陣列後面追加元素,返回的slice和原來的slice是同一個物件。顯然,這種情況下原來的slice的值會發生變化!
2. 如果nums的cap不夠用(上述程式碼就是這種情況),則會重新分配一個數組空間用來儲存資料,並且返回指向新陣列的slice。這時候原來的slice指向的陣列並沒有發生任何變化!
3. 當然,在任何情況下,返回的結果都是追加之後的slice,這一點沒有問題!

以下程式碼用來驗證這個問題:
(1)在函式test1nums的值發生變化了,因為nums[:2]的len為2,cap為3,所以追加一個元素時cap依然夠用;
(2)在函式test2nums的值沒有發生變化,因為nums[:2]的cap不夠用,因此會重新分配一個數組用來儲存新的資料,而nums儲存的仍然是老陣列。

func test1() {
    nums := []int{1, 2, 3}
    _ = append(nums[:2], 4)
    fmt.Println("test1:", nums)

    //nums changes because the cap is big enought, the original array is modified.

}

func test2() {
    nums := []int{1
, 2, 3} c := append(nums[:2], []int{4, 5, 6}...) fmt.Println("test2:", nums) fmt.Println("cc:", c) //nums dont't change because the cap isn't big enought. //a new array is allocated while the nums still points to the old array. //Of course, the return value of append points to the new array. }

4.為了避開這個’坑’,推薦在擷取slice時使用三引數的方式,示例程式碼:

func main() {
    nums:=[]int{1,2,3,4,5}
    fmt.Println("111---len:",len(nums),"cap:",cap(nums))

    a:=nums[:3]
    fmt.Println("222---",len(a),cap(a))
    //output: 222--- 3 5

    b:=nums[:3:3]
    fmt.Println("333---",len(b),cap(b))
    //output: 333--- 3 3
}

從輸出結果可以看出,使用三引數方式時,擷取後的slice的cap將會重新設定。如果第二個引數和第三個引數相同,那麼擷取後的slice的len==cap,這樣在執行append的時候一定會重新分配陣列,從而保證原始的陣列(nums)不會發生變化。

<完結>

相關推薦

Golangsliceappend陣列發生變化的問題

使用append可以在slice之後追求元素,例如 nums:=[]int{1,2,3} result:=append(nums,4) fmt.Println(result) 這段程式碼很簡單,輸出result的值為:[1 2 3 4] 問題在於,進行

shell文字過濾程式設計(六)awk迴圈判斷及陣列

與上一節printf一樣,awk的迴圈判斷和C語言的迴圈判斷語法極其類似。 1、 While迴圈 #!/bin/sh awk ' BEGIN { ORS="" } { i=0 while (i < NF) { printf

滑鼠經過input的顏色發生變化

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http:

Java:假設車庫有3個車位(可以通過boolean[]陣列來表示車庫)可以停車,寫一個程式模擬多個使用者開車離開,停車入庫的效果。注意車位有車不能停車。

假設車庫有3個車位(可以通過boolean[]陣列來表示車庫)可以停車,寫一個程式模擬多個使用者開車離開,停車入庫的效果。注意:車位有車時不能停車。 1)使用阻塞佇列來實現(BlockingQueue<T>) Producer類 package com.多執行緒停車問

C++對結構體中字元陣列賦值,出現表示式必須是可修改的左值的問題

問題描述:         在C++中為結構體中的字元陣列賦值時,出現”表示式必須是可修改的左值“的錯誤提醒,編譯報錯“不可指定資料型別”。           &n

JavaScript中不改變陣列的方法

concat:把兩個或多個數組拼接,產生一個新的陣列 var arr = [1,2,3,4,5]; var arr1 = [7,8,9]; slice:(從該位開始擷取,擷取到該位),不改變原陣列,所以要返回該值。 分別有三種情況: 兩位引數: var ar

Golang從入門到精通(六)Golang控制語句for

for結構介紹 Go語言只有for迴圈這一種迴圈結構。 基本的for迴圈包含三個由分號分開的組成部分: 1.初始化語句:在第一次迴圈執行前被執行 2.迴圈條件表示式:每輪迭代開始前被求值 3.後置語句:每輪迭代後被執行 初始化語句一般是一個短變數宣告

js陣列賦值不修改陣列,返回新的陣列

有一個數組arr = [1, 2, 3, 4, 10]。 var str = new Array; str = arr; //這個不是賦值,將陣列arr的引用賦給str,所以改變str也會改變arr (js實際建立的str是一個物件); 正確賦值:

Golang從入門到精通(十八)Golang併發程式設計Goroutine

程序,執行緒,並行和併發 一個應用程式是執行在機器上的一個程序;程序是一個執行在自己記憶體地址空間裡的獨立執行體。一個程序由一個或多個作業系統執行緒組成,這些執行緒其實是共享同一個記憶體地址空間的一起工作的執行體。幾乎所有’正式’的程式都是多執行緒的,以便讓使

C語言Struct結構陣列以及結構的巢狀

一、結構陣列為什麼要使用結構陣列?舉個例子來說,假如我們定義了一個結構體book,顯然每一本書都可以用一個book型別的結構體來描述。要描述兩本書就需要用兩個這樣的結構變數,以此類推,如果我們要處理10本,100本,1000本...我們難道要一個一個定義嗎?我們想到陣列這種資

Golang從入門到精通(十九)Golang併發程式設計Channel

Go語言併發模型 Go 語言中使用了CSP模型來進行執行緒通訊,準確說,是輕量級執行緒goroutine之間的通訊。CSP模型和Actor模型類似,也是由獨立的,併發執行的實體所構成,實體之間也是通過傳送訊息進行通訊的。 Actor模型和CSP模型區別 A

Unity3D開發(二)NGUIUIButton"禁用"狀態置灰

NGUI中的Button幾乎是最常用到的控制元件之一,並且可以組合各種元件(比如UIButtonColor,UIButtonOffset,UITweenxx),方便設定Button的各種狀態下的屬性,幾乎可以滿足我們的所有需求。 但是對於當Button的isEnabled屬

Golang從入門到精通(七)Golang控制語句switch

基本結構 相比較 C 和 Java 等其它語言而言,Go 語言中的 switch 結構使用上更加靈活。它接受任意形式的表示式,例如: switch var1 { case val1: ... case val2:

Django編輯根據條件跳轉回頁面

在要跳轉的編輯頁面: #首先獲取當期的url: curr_url = self.request.GET.urlencode() #建立一個QueryDict物件: params = QueryD

[Golang]slice的用法以及和陣列的區別

說明 slice是go的一個語言特性,其實有點類似於cpp的vector,可變長度,可以擴充套件空間。今天詳細看了下,做下總結。 slice本質上是一個區間,原型是[]T,大致的實現是這樣的: type slice struct { f

ActiveMQ(18)Message延遲和定時消息投遞

jms activemq 延遲和定時消息投遞 一、簡介延遲和定時消息投遞(Delay and Schedule Message Delivery) 有時候我們不希望消息馬上被broker投遞出去,而是想要消息60秒以後發給消費者,或者我們想讓消息沒隔 一定時間投遞一次,一共投遞指定的次數。。。

RabbitMQ學習筆記五RabbitMQ優先級消息隊列

-c virtual 調用 itl 3.5 rri color images 執行順序 RabbitMQ優先級隊列註意點: 1、只有當消費者不足,不能及時進行消費的情況下,優先級隊列才會生效 2、RabbitMQ3.5以後才支持優先級隊列 代碼在博客:RabbitMQ學習筆

《大型網站技術架構》讀書筆記永無止境網站的伸縮性架構

映射 應對 方法 訂閱 知識 位置 n+1 轉換 bsp 此篇已收錄至《大型網站技術架構》讀書筆記系列目錄貼,點擊訪問該目錄可獲取更多內容。 首先,所謂網站的伸縮性,指不需要改變網站的軟硬件設計,僅僅通過改變部署的服務器數量就可以擴大或者縮小網站的服務處理能力。在整個互聯

設計趨勢網頁粗糲設計風格

現在 專家 能夠 com 如果 這樣的 isp 藝術 配色 我們看到過許多精心炮制,細節到位的高素質的設計作品,但並不是所有的設計都是如此。有一些並不是那麽精細到位,相反是以粗糙和狂野為賣點的網頁,同樣讓人難以忘懷。這些被歸類於“粗野主義”的設計作品,在今年再一次悄然流行。