《Go題庫·1》Golang里的數(shù)組和切片有了解過嗎?

題目來源: 深信服师妙、知乎诵肛、跟誰學(xué)

題目解析: GOALNG ROADMAP社區(qū)

答案 1:(溪尾)

數(shù)組長度是固定的,而切片是可變長的默穴≌荩可以把切片看作是對底層數(shù)組的封裝,每個切片的底層數(shù)據(jù)結(jié)構(gòu)中蓄诽,一定會包含一個數(shù)組薛训。數(shù)組可以被稱為切片的底層數(shù)組,切片也可以被看作對數(shù)組某一連續(xù)片段的引用仑氛。因此乙埃,Go 中切片屬于引用類型蝴猪,而數(shù)組屬于值類型,通過內(nèi)建函數(shù) len膊爪,可以取得數(shù)組和切片的長度。通過內(nèi)建函數(shù) cap嚎莉,可以得到數(shù)組和切片的容量米酬。但是數(shù)組的長度和容量是相等的,并且都不可變趋箩,而且切片容量是有變化規(guī)律的赃额。

答案 2:(行飛子)

數(shù)組和切片的關(guān)系:

切片一旦初始化, 切片始終與保存其元素的基礎(chǔ)數(shù)組相關(guān)聯(lián)叫确。因此跳芳,切片會和與其擁有同一基礎(chǔ)數(shù)組的其他切片共享存儲 ; 相比之下,不同的數(shù)組總是代表不同的存儲竹勉。

數(shù)組和切片的區(qū)別

  1. 切片的長度可能在執(zhí)行期間發(fā)生變化 飞盆,而數(shù)組的長度不能變化,可以把切片看成一個長度可變的數(shù)組次乓。

  2. 數(shù)組作為函數(shù)參數(shù)是進(jìn)行值傳遞的吓歇,函數(shù)內(nèi)部改變傳入的數(shù)組元素值不會影響函數(shù)外部數(shù)組的元素值; 切片作為函數(shù)的參數(shù)是進(jìn)行的指針傳遞票腰,函數(shù)內(nèi)部改變切片的值會影響函數(shù)外部的切片元素值城看。

  3. 數(shù)組可以比較,切片不能比較(對底層數(shù)組的引用)杏慰。

答案 3:(欒龍生)

1. Go 切片和 Go 數(shù)組

Go 切片测柠,又稱動態(tài)數(shù)組,它實(shí)際是基于數(shù)組類型做的一層封裝缘滥。

Go 數(shù)組

數(shù)組是內(nèi)置(build-in)類型,是一組同類型數(shù)據(jù)的集合轰胁,它是值類型,通過從 0 開始的下標(biāo)索引訪問元素值朝扼。在初始化后長度是固定的软吐,無法修改其長度。當(dāng)作為方法的參數(shù)傳入時將復(fù)制一份數(shù)組而不是引用同一指針吟税。數(shù)組的長度也是其類型的一部分凹耙,通過內(nèi)置函數(shù) len(array)獲取其長度。

Go 數(shù)組與像 C/C++等語言中數(shù)組略有不同肠仪,如下

  • Go 中的數(shù)組是值類型肖抱,換句話說,如果你將一個數(shù)組賦值給另外一個數(shù)組异旧,那么意述,實(shí)際上就是將整個數(shù)組拷貝一份。因此,在 Go 中如果將數(shù)組作為函數(shù)的參數(shù)傳遞的話荤崇,那效率就肯定沒有傳遞指針高了拌屏。
  • 數(shù)組的長度也是類型的一部分,這就說明[10]int[20]int不是同一種數(shù)據(jù)類型术荤。

Go 切片

Go 語言中數(shù)組的長度是固定的倚喂,且不同長度的數(shù)組是不同類型,這樣的限制帶來不少局限性瓣戚。

而切片則不同端圈,切片(slice)是一個擁有相同類型元素的可變長序列,可以方便地進(jìn)行擴(kuò)容和傳遞子库,實(shí)際使用時比數(shù)組更加靈活舱权,這也正是切片存在的意義。

切片是引用類型仑嗅,因此在當(dāng)傳遞切片時將引用同一指針宴倍,修改值將會影響其他的對象。

2. 切片底層

現(xiàn)在就來看一下 Go 語言切片的底層是什么樣子吧仓技!

Go 切片(slice)的實(shí)現(xiàn)可以在源碼包src/runtime/slice.go中找到啊楚。在源碼中,slice 的數(shù)據(jù)結(jié)構(gòu)定義如下浑彰。

type slice struct {
    array unsafe.Pointer    //指向底層數(shù)組的指針
    len int                 //切片長度
    cap int                 //切片容量
}

可以看到恭理,組成 Go 切片的三元組分別為指向底層數(shù)組的指針,切片長度和切片容量郭变。

  1. 指向底層數(shù)組的指針

    前面已經(jīng)提到颜价,切片實(shí)際是對數(shù)組的一層封裝。這個指針便是記錄其底層數(shù)組的地址诉濒,也正是切片開始的位置周伦。

  2. 切片長度

    len表示切片的長度,即切片中現(xiàn)存有效元素的個數(shù)未荒,它不能超過切片的容量专挪。可以通過len()函數(shù)獲取切片長度片排。

  3. 切片容量

    cap表示切片的容量寨腔,即切片能存儲元素的多少,通常是從切片的起始元素到底層數(shù)組的最后一個元素間的元素個數(shù)率寡,當(dāng)切片容量不足時迫卢,便會觸發(fā) slice 擴(kuò)容∫惫玻可以通過cap()函數(shù)獲取切片容量乾蛤。

下圖展示了一個 Go 切片的底層數(shù)據(jù)結(jié)構(gòu)每界,這個切片的長度為 3,容量為 6家卖。

3. 切片使用

  1. 切片定義方式
   var a []int                  //nil切片眨层,和nil相等,一般用來表示一個不存在的切片
   var b []int{}                //空切片上荡,和nil不相等趴樱,一般用來表示一個空的集合
   var c []int{1, 2, 3}     //有3個元素的切片,len和cap都為3
   var d = c[:2]                //有2個元素的切片榛臼,len為2,cap為3
   var e = c[:2:cap(c)]     //有2個元素的切片窜司,len為2沛善,cap為3
   var f = c[:0]                //有0個元素的切片,len為0塞祈,cap為3
   var g = make([]int, 3)       //創(chuàng)建一個切片金刁,len和cap均為3
   var h = make([]int, 3, 6)    //創(chuàng)建一個切片,len為3议薪,cap為5
   var i = make([]int, 0, 3)    //創(chuàng)建一個切片尤蛮,len為0,cap為3
  1. 從數(shù)組中切取切片

    數(shù)組和切片是緊密相連的斯议。切片可以用來訪問數(shù)組的部分或全部元素产捞,而這個數(shù)組稱為切片的底層數(shù)組。切片的指針指向數(shù)組第一個可以從切片中訪問的元素哼御,這個元素并不一定是數(shù)組的第一個元素坯临。

    一個底層數(shù)組可以對應(yīng)多個切片,這些切片可以引用數(shù)組的任何位置恋昼,彼此之前的元素可以重疊看靠。

    slice 操作符 s[i:j] 創(chuàng)建了一個新的 slice,這個新的 slice 引用了 s 中從 i 到 j-1 索引位置的所有元素液肌。

    如果表達(dá)式省略了 i挟炬,那么默認(rèn)是s[0:j];如果省略了 j嗦哆,默認(rèn)是s[i:len(s)]谤祖;

  //示例來源:The Go Programming Language
  //創(chuàng)建一個數(shù)組
  months := [...]string{1:"January", /*...*/, 12: "December"}
  Q2 := months[4:7]
  summer := months[6:9]
  fmt.Println(Q2)               //["April" "May" "June"]
  fmt.Println(summer)           //["June" "July" "August"]

月份名稱字符串?dāng)?shù)組與其對應(yīng)的兩個元素重疊的 slice 圖示

注意:切片與原數(shù)組或切片共享底層空間,修改切片會影響原數(shù)組或切片

  1. 迭代切片

    切片可以用 range 迭代老速,但是要注意:如果只用一個值接收 range泊脐,則得到的只是切片的下標(biāo),用兩個值接收 range烁峭,則得到的才是下標(biāo)和對應(yīng)的值容客。

   //使用一個值接收range, 則得到的是切片的下標(biāo)
   for i := range months {
    fmt.Println(i)      //返回下標(biāo) 0 1 ... 12
   }
   //使用兩個值接收range秕铛,則得到的是下標(biāo)和對應(yīng)的值
   for i, v := range months {
    fmt.Println(i, v)   //返回下標(biāo)0 1 ... 12 和 值 "" "January" ... "December"
   }
  1. 切片拷貝

    使用copy內(nèi)置函數(shù)拷貝兩個切片時,會將源切片的數(shù)據(jù)逐個拷貝到目的切片指向的數(shù)組中缩挑,拷貝數(shù)量取兩個切片的最小值但两。

    例如長度為 10 的切片拷貝到長度為 5 的切片時,將拷貝 5 個元素供置。也就是說谨湘,拷貝過程中不會發(fā)生擴(kuò)容。

    copy 函數(shù)有返回值芥丧,它返回實(shí)際上復(fù)制的元素個數(shù)紧阔,這個值就是兩個 slice 長度的較小值。

4. 切片擴(kuò)容-append 函數(shù)

追加元素

  • 通過append()函數(shù)可以在切片的尾部追加 N 個元素
  var a []int
  a = append(a, 1)                  // 追加一個元素
  a = append(a, 1, 2, 3)                // 追加多個元素
  a = append(a, []int{1, 2, 3}...)  // 追加一個切片续担,注意追加切片時后面要加...
  • 使用 append()函數(shù)也可以在切片頭部添加元素
  a = append([]int{0}, a...)            // 在開頭添加一個元素
  a = append([]int{1, 2, 3}, a...)  // 在開頭添加一個切片

注:從頭部添加元素會引起內(nèi)存的重分配擅耽,導(dǎo)致已有元素全部復(fù)制一次。因此從頭部添加元素的開銷要比從尾部添加元素大很多

  • 通過 append()函數(shù)鏈?zhǔn)讲僮鲝闹虚g插入元素
  a = append(a[:i], append([]int{x}, a[i:]...)...)      //在第i個位置上插入x
  a = append(a[:i], append([]int{1, 2, 3}, a[i:]...)...)    //在第i個位置上插入切片

使用鏈?zhǔn)讲僮髟诓迦朐匚镉觯趦?nèi)層 append 函數(shù)中會創(chuàng)建一個臨式切片乖仇,然后將a[i:]內(nèi)容復(fù)制到新創(chuàng)建的臨式切片中,再將臨式切片追加至a[:i]中询兴。

  • 通過 append()和 copy()函數(shù)組合從中間插入元素

    使用這種方式可以避免創(chuàng)建過程中間的臨式切片乃沙,也可以做到從中間插入元素

  //中間插入一個元素
  a = append(a, 0)          //切片擴(kuò)展一個空間
  copy(a[i+1:], a[i:])      //a[i:]向后移動一個位置
  a[i] = x                  //設(shè)置新添加的元素
  //中間插入多個元素
  a = append(a, x...)           //為x切片擴(kuò)展足夠的空間
  copy(a[i+len(x):], a[i:]) //a[i:]向后移動len(x)個位置
  copy(a[i:], x)                //復(fù)制新添加的切片

使用此方式雖然稍顯復(fù)雜,但是可以減少創(chuàng)建中間臨時切片的開銷诗舰。

刪除元素

很遺憾警儒,Go 語言中并沒有提供直接刪除指定位置元素的方式。不過根據(jù)切片的性質(zhì)眶根,我們可以通過巧妙的拼接切片來達(dá)到刪除指定數(shù)據(jù)的目的冷蚂。

a = []int{1, 2, 3}
//刪除尾部元素
a = a[:len(a) - 1]              //刪除尾部一個元素
a = a[:len(a) - N]              //刪除尾部N個元素
//刪除頭部元素
a = [1:]                        //刪除開頭1個元素
a = [N:]                        //刪除開頭N個元素
//刪除中間元素
a = append(a[:i], a[i+1:]...)   //刪除中間一個元素
a = append(a[:i], a[i+N:]...)   //刪除中間N個元素

slice 擴(kuò)容

很多人以為 slice 是可以自動擴(kuò)充的, 估計(jì)都是 append 函數(shù)誤導(dǎo)的。其實(shí) slice 并不會自己自動擴(kuò)充, 而是 append 數(shù)據(jù)時, 該函數(shù)如果發(fā)現(xiàn)超出了 cap 限制自動幫我們擴(kuò)的汛闸。

使用 append 向 slice 追加元素時蝙茶,如果 slice 空間不足,則會觸發(fā) slice 擴(kuò)容诸老,擴(kuò)容實(shí)際上是分配一塊更大的內(nèi)存隆夯,將原 slice 的數(shù)據(jù)拷貝進(jìn)新 slice,然后返回新 slice别伏,擴(kuò)容后再將數(shù)據(jù)追加進(jìn)去蹄衷。

例如,當(dāng)向一個容量為 5 且長度也為 5 的切片再次追加 1 個元素時厘肮,就會發(fā)生擴(kuò)容愧口,如下圖所示。(示例來源:Go專家編程)

擴(kuò)容操作只關(guān)心容量类茂,會把原 slice 的數(shù)據(jù)拷貝至新 slice 中耍属,追加數(shù)據(jù)由 append 在擴(kuò)容后完成托嚣。由上圖可見,擴(kuò)容后新 slice 的長度仍然是 5厚骗,但容量由 5 提到了 10示启,原 slice 的數(shù)據(jù)也都拷貝到了新的 slice 指向的數(shù)組中。

擴(kuò)容容量的選擇遵循以下基本規(guī)則

  • 如果原 slice 的容量小于 1024领舰,則新 slice 的容量將擴(kuò)大為原來的 2 倍夫嗓;
  • 如果原 slice 的容量大于 1024,則新的 slice 的容量將擴(kuò)大為原來的 1.25 倍冲秽;

5. Go 切片舍咖,Python 切片,都是切片锉桑,有什么不同排霉?

Go 有切片 slice 類型,Python 有列表和元組刨仑,這兩種語言都有切片操作郑诺。但是它們的切片操作是完全不同的夹姥。

  1. 最大的不同就是
  • Python 的切片產(chǎn)生的是新的對象杉武,對新對象的成員的操作不影響舊對象;
  • Go 的切片產(chǎn)生的是舊對象一部分的引用辙售,對其成員的操作會影響舊對象轻抱;

究其原因還是底層實(shí)現(xiàn)不同

  • Go 的切片,底層是一個三元組旦部。指針指向一塊連續(xù)的內(nèi)存祈搜,長度是已有成員數(shù),容量是最大成員數(shù)士八。切片時容燕,一般并不會申請新的內(nèi)存,而是對原指針進(jìn)行移動婚度,然后和新的長度蘸秘、容量組成一個切片類型值返回。也就是說蝗茁,Go 的切片操作通常會和生成該切片的切片或數(shù)組共享內(nèi)存醋虏。
  • Python 的切片,其實(shí)就是指針數(shù)組哮翘。對它進(jìn)行切片颈嚼,會創(chuàng)建新的數(shù)組。在 Python 的切片中饭寺,并沒有容量的概念叫挟。

這其實(shí)也體現(xiàn)了腳本語言和編譯語言的不同。雖然兩個語言都有類似的切片操作霞揉;但是 Python 主要目標(biāo)是方便;Go 主要目標(biāo)卻是快速适秩。

  1. 在使用中,Go 切片和 Python 切片也有很多不同
  • 首先秽荞,Go 的切片,其成員是相同類型的抚官,Python 的列表則不限制類型。

  • 兩種語言都有[a:b]這種切片操作凌节,意義也類似,但是 Go 的 a倍奢、b 兩個參數(shù)不能是負(fù)數(shù)朴上,Python 可以是負(fù)數(shù),此時就相當(dāng)于從末尾往前數(shù)卒煞。

  • 兩種語言都有[a:b:c]這種切片操作痪宰,意義卻是完全不同的。Go 中的 c 表示的是容量畔裕;而 Python 的 c 表示的是步長衣撬。

6. 切片陷阱

  1. 無法做比較

    和數(shù)組不同的是,slice 無法做比較扮饶,因此不能用==來測試兩個 slice 是否擁有相同的元素具练。標(biāo)準(zhǔn)庫里面提供了高度優(yōu)化的函數(shù)bytes.Equal來比較兩個字節(jié) slice。但是對于其它類型的 slice甜无,就必須要自己寫函數(shù)來比較扛点。

    slice 唯一允許的比較操作是和 nil 進(jìn)行比較,例如

   if slice == nil {/*...*/}
  1. 空切片和 nil 切片

    空切片和 nil 切片是不同的毫蚓。

    • nil 切片中占键,切片的指針指向的是空地址,其長度和容量都為零元潘。nil 切片和 nil 相等畔乙。
    • 空切片,切片的指針指向了一個地址翩概,但其長度和容量也為 0牲距,和 nil 不相等返咱,通常用來表示一個空的集合。
    var s []int             // s == nil
    var s = nil             // s == nil
    var s = []int{nil}          // s == nil
    var s = []int{}         // s != nil
    s := make([]int,0)          // s != nil
  1. 使用 range 進(jìn)行切片迭代

    當(dāng)使用 range 進(jìn)行切片迭代時牍鞠,range 創(chuàng)建了每個元素的副本咖摹,而不是直接返回對該元素的引用。如果使用該值變量的地址作為每個元素的指針难述,就會造成錯誤萤晴。

   func main() {
    a := []int{1, 2, 3, 4, 5}

    for i, v := range a {
        fmt.Printf("Value: %d, v-addr: %X, Elem-addr: %X\n",
            v, &v, &a[i])
    }
   }
   # output
   Value: 1, v-addr: C0000AA058, Elem-addr: C0000CC030
   Value: 2, v-addr: C0000AA058, Elem-addr: C0000CC038
   Value: 3, v-addr: C0000AA058, Elem-addr: C0000CC040
   Value: 4, v-addr: C0000AA058, Elem-addr: C0000CC048
   Value: 5, v-addr: C0000AA058, Elem-addr: C0000CC050

從結(jié)果中可以看出,使用 range 進(jìn)行迭代時胁后,v 的地址是始終不變的店读,它并不是切片中每個變量的實(shí)際地址攀芯。而是在使用 range 進(jìn)行遍歷時,將切片中每個元素都復(fù)制到了同一個變量 v 中殖演。如果錯誤的將 v 的地址當(dāng)作切邊元素的地址年鸳,將會引發(fā)錯誤。

  1. 切片擴(kuò)容引發(fā)的問題

    正因?yàn)橛袛U(kuò)容機(jī)制朋鞍。所以我們無法保證原始的 slice 和用 append 后的結(jié)果 slice 指向同一個底層數(shù)組妥箕,也無法證明它們就指向不同的底層數(shù)組更舞。同樣,我們也無法假設(shè)舊 slice 上對元素的操作會或者不會影響新的 slice 元素宇葱。所以黍瞧,通常我們將 append 的調(diào)用結(jié)果再次賦給傳入 append 的 slice原杂。

    內(nèi)置 append 函數(shù)在向切片追加元素時,如果切片存儲容量不足以存儲新元素年局,則會把當(dāng)前切片擴(kuò)容并產(chǎn)生一個新的切片。

    append 函數(shù)每次追加元素都有可能觸發(fā)切片擴(kuò)容矢否,即有可能返回一個新的切片,這正是 append 函數(shù)聲明中返回值為切片的原因赖欣,使用時應(yīng)該總是接收該返回值验庙。

    建議

    使用 append 函數(shù)時,謹(jǐn)記 append 可能會產(chǎn)生新的切片云矫,并謹(jǐn)慎的處理返回值汗菜。

  2. append 函數(shù)誤用

    使用 append 函數(shù)時,需要考慮 append 返回的切片是否跟原切片共享底層的數(shù)組巡揍。下面這段程序片段菌瘪,來看看函數(shù)返回的結(jié)果。

   //示例來源:Go專家編程
   func AppendDemo() {
    x := make([]int, 0, 10)
    x = append(x, 1, 2, 3)
    y := append(x, 4)
    z := append(x, 5)
    fmt.Println(x)
    fmt.Println(y)
    fmt.Println(z)
   }

   //output
   [1 2 3]
   [1 2 3 5]
   [1 2 3 5]

題目首先創(chuàng)建了一個長度為 0糜工,容量為 10 的切片 x录淡,然后向切片 x 追加了 1,2刨裆,3 三個元素彬檀。其底層的數(shù)組結(jié)構(gòu)如下圖所示

創(chuàng)建切片 y 為切片 x 追加一個元素 4 后窍帝,底層數(shù)組結(jié)構(gòu)如下圖所示

需要注意的是切片 x 仍然沒有變化,切片 x 中記錄的長度仍為 3慈俯。繼續(xù)向 x 追加元素 5 后,底層數(shù)組結(jié)構(gòu)如下圖所示

至此卖子,答案已經(jīng)非常明確了洋闽。當(dāng)向 x 繼續(xù)追加元素 5 后突梦,切片 y 的最后一個元素被覆蓋掉了。

此時切片 x 仍然為[1 2 3]刊懈,而切片 y 和 z 則為[1 2 3 5]娃闲。

建議

一般情況下,使用 append 函數(shù)追加新的元素時皇帮,都會用原切片變量接收返回值來獲得更新

   a = append(a, elems...)
  1. 函數(shù)傳參

    Go 語言中將切片作為函數(shù)參數(shù)傳遞會有什么神奇的現(xiàn)象,一起來看看下面這個示例将谊。

   package main

   import "fmt"

   func main(){
       a := []int{1, 2, 3}              //長度為3渐白,容量為3
       b := make([]int, 1, 10)      //長度為1,容量為10
       test(a,b)
        fmt.Println("main a =", a)
       fmt.Println("main b =", b)
   }

   func test(a,b []int){
       a = append(a, 4)             //引發(fā)擴(kuò)容眠砾,此時返回的a是一個新的切片
       b = append(b, 2)             //沒有引發(fā)擴(kuò)容托酸,仍然是原切片
       a[0] = 3                     //改變a切片元素
       b[0] = 3                     //改變b切片元素
       fmt.Println("test a =", a)       //打印函數(shù)內(nèi)的a切片
       fmt.Println("test b =", b)       //打印函數(shù)內(nèi)的b切片
   }

   //output
   test a = [3 2 3 4]
   test b = [3 2]
   main a = [1 2 3]
   main b = [3]

首先励堡,我們創(chuàng)建了兩個切片堡掏,a 切片長度和容量均為 3,b 切片長度為 1鹅龄,容量為 10。將 a 切片和 b 切片作為函數(shù)參數(shù)傳入 test 函數(shù)中迎卤。

在 test 函數(shù)中玷坠,對 a 切片和 b 切片做了如下兩點(diǎn)改動

  1. 分別使用 append 函數(shù)在 a 切片和 b 切片中追加一個元素

  2. 分別對 a 切片和 b 切片的第一個元素做了修改

分別在主函數(shù)中和 test 函數(shù)中輸出兩個切片,會發(fā)現(xiàn)在主函數(shù)中和 test 函數(shù)中兩個切片好像改了樟凄,又好像沒改兄渺,下面我們就來分析一下。

理論分析

當(dāng)我們將一個切片作為函數(shù)參數(shù)傳遞給函數(shù)的時候,采用的是值傳遞凳兵,因此我們傳遞給函數(shù)的參數(shù)其實(shí)是上面這個切片三元組的值拷貝。當(dāng)我們對切片結(jié)構(gòu)中的指針進(jìn)行值拷貝的時候饭望,得到的指針還是指向了同一個底層數(shù)組形庭。因此我們通過指針對底層數(shù)組的值進(jìn)行修改,從而修改了切片的值斟珊。

但是富纸,當(dāng)我們以值傳遞的方式傳遞上面的結(jié)構(gòu)體的時候,同時也是傳遞了lencap的值拷貝堵漱,因?yàn)檫@兩個成員并不是指針涣仿,因此示惊,當(dāng)我們從函數(shù)返回的時候米罚,外層切片結(jié)構(gòu)體的lencap這兩個成員并沒有改變丈探。

所以當(dāng)我們傳遞切片給函數(shù)的時候,并且在被調(diào)函數(shù)中通過append操作向切片中增加了值糊肠,但是當(dāng)函數(shù)返回的時候遗锣,我們看到的切片的值還是沒有發(fā)生變化,其實(shí)底層數(shù)組的值是已經(jīng)改變了的(如果沒有觸發(fā)擴(kuò)容的話)弧圆,但是由于長度len沒有發(fā)生改變搔预,所以我們看到的切片的值也沒有發(fā)生改變叶组。

題目再分析

有了前面的理論基礎(chǔ),我們再來分析一下 a船庇,b 切片的返回結(jié)果侣监。

  1. a 切片作為參數(shù)傳至 test 函數(shù)中,在 test 中向 a 切片追加一個元素后窃爷,此時觸發(fā)擴(kuò)容機(jī)制姓蜂,返回的切片已經(jīng)不再是原切片,而是一個新的切片覆糟。后續(xù)對 a 切片中的第一個元素進(jìn)行修改也是對新切片進(jìn)行修改,對老切片不會產(chǎn)生任何影響。

    所以,最終在主函數(shù)中 a 切片仍然為[1 2 3]漓藕,而在 test 函數(shù)中 a 切片變成了[3 2 3 4]挟裂。

  2. b 切片作為參數(shù)傳至 test 函數(shù)中,在 test 中向 b 切片追加一個元素后栗竖,不會觸發(fā)擴(kuò)容機(jī)制渠啤,返回的仍然是原切片,所以在后續(xù)對 b 切片的修改都是在原切片中進(jìn)行的修改份名。故在 test 函數(shù)中 b 切片為[3 2]妓美。但是在主函數(shù)中確為[3],可以看出在 test 中對切片進(jìn)行修改確實(shí)反應(yīng)到主函數(shù)中了辰如,但是由于其 len 和 cap 沒有改變贵试,len 仍為 1,所以最終就只輸出切片中的第一個元素[3]呕童,但其底層數(shù)組的值其實(shí)已經(jīng)改變了夺饲。

本文由 GOLANG ROADMAP 發(fā)布施符!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浩销,隨后出現(xiàn)的幾起案子听哭,更是在濱河造成了極大的恐慌塘雳,老刑警劉巖败明,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件太防,死亡現(xiàn)場離奇詭異,居然都是意外死亡讳嘱,警方通過查閱死者的電腦和手機(jī)酿愧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門寓娩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寞埠,你說我怎么就攤上這事焊夸。” “怎么了阱穗?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵揪阶,是天一觀的道長。 經(jīng)常有香客問我炊苫,道長冰沙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任唠梨,我火速辦了婚禮侥啤,結(jié)果婚禮上茬故,老公的妹妹穿的比我還像新娘均牢。我一直安慰自己才睹,他們只是感情好甘邀,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布松邪。 她就那樣靜靜地躺著,像睡著了一般剧辐。 火紅的嫁衣襯著肌膚如雪邮府。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天忍啤,我揣著相機(jī)與錄音仙辟,去河邊找鬼。 笑死叠国,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冤狡。 我是一名探鬼主播吆玖,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼沾乘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歪玲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岖圈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜂科,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體短条,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茸时,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年可都,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旋炒。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘱兼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出汇四,到底是詐尸還是另有隱情踢涌,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布背苦,位于F島的核電站潘明,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏厚宰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一澈蝙、第九天 我趴在偏房一處隱蔽的房頂上張望撵幽。 院中可真熱鬧,春花似錦逗载、人聲如沸况褪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽食侮。三九已至目胡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間誉己,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工噪猾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筑累,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓坪蚁,卻偏偏與公主長得像镜沽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嘴脾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容