Go語言學(xué)習(xí)七:slice

1. slice 擴(kuò)容機(jī)制

如果 Slice 要擴(kuò)容的容量大于 2 倍當(dāng)前的容量恕曲,則直接按想要擴(kuò)容的容量來 new 一個(gè)新的 Slice杂彭,否則繼續(xù)判斷當(dāng)前的長度 len岩喷,如果 len 小于 1024视事,則直接按 2 倍容量來擴(kuò)容匈勋,否則一直循環(huán)新增 1/4礼旅,直到大于想要擴(kuò)容的容量

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
    newcap = cap
} else {
    if old.len < 1024 {
        newcap = doublecap
    } else {
        for newcap < cap {
            newcap += newcap / 4
        }
    }
}

實(shí)際使用

// =========== 第一種

a := make([]string, 5)
fmt.Println(len(a), cap(a))   //  輸出5   5

a = append(a, "aaa")
fmt.Println(len(a), cap(a))   // 輸出6  10


// 總結(jié): 由于make([]string, 5) 則默認(rèn)會(huì)初始化5個(gè) 空的"", 因此后面 append 時(shí),則需要2倍了


// =========== 第二種
a:=[]string{}
fmt.Println(len(a), cap(a))   //  輸出0   0

a = append(a, "aaa")
fmt.Println(len(a), cap(a))   // 輸出1  1

// 總結(jié):由于[]string{}, 沒有其他元素洽洁, 所以append 按 需要擴(kuò)容的 cap 來

// =========== 第三種
a := make([]string, 0, 5)
fmt.Println(len(a), cap(a))   //  輸出0   5

a = append(a, "aaa")
fmt.Println(len(a), cap(a))   // 輸出1  5

// 總結(jié):注意和第一種的區(qū)別痘系,這里不會(huì)默認(rèn)初始化5個(gè),所以后面的append容量是夠的饿自,不用擴(kuò)容

// =========== 第四種
b := make([]int, 1, 3)
a := []int{1, 2, 3}
copy(b, a)

fmt.Println(len(b))  // 輸出1

// 總結(jié):copy 取決于較短 slice 的 len, 一旦最小的len結(jié)束了汰翠,也就不再復(fù)制了

2.slice range 相關(guān)分析

下面代碼段 是否陷入死循環(huán)?

v := []int{1, 2, 3}
for i := range v {
 v = append(v, i)
}

上面代碼的執(zhí)行是不會(huì)一直循環(huán)下去的昭雌,原因在于 range 的時(shí)候會(huì) copy 這個(gè) slice 上的 len 屬性到一個(gè)新的變量上复唤,然后根據(jù)這個(gè) copy 值去遍歷 slice,因此遍歷期間即使 slice 添加了元素城豁,也不會(huì)改變這個(gè)變量的值了苟穆。
參考 range slice 源代碼

// The loop we generate:
//   for_temp := range
//   len_temp := len(for_temp)
//   for index_temp = 0; index_temp < len_temp; index_temp++ {
//           value_temp = for_temp[index_temp]
//           index = index_temp
//           value = value_temp
//           original body
//   }

map range 的情況時(shí)如何?

    m1 := make(map[string]string, 0)
    m1["name"] = "jack"
    for k, v := range m1 {
        log.Println(k, v)
        m1[fmt.Sprintf("%v_%v", k, 1)] = v
    }
這段代碼代碼輸出結(jié)果是不固定的唱星,原因是 map實(shí)現(xiàn)是基于hash 表實(shí)現(xiàn)的雳旅,插入數(shù)據(jù)的位置是不固定的,遍歷過程中不保證一定遍歷到新插入的數(shù)據(jù)

map range 源碼:
//   var hiter map_iteration_struct
//   for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter) {
//           index_temp = *hiter.key
//           value_temp = *hiter.val
//           index = index_temp
//           value = value_temp
//           original body
//   }

3. 注意事項(xiàng)

  • range 一個(gè) slice 的時(shí)候是進(jìn)行一個(gè)值拷貝的间聊,如果 slice 里存儲(chǔ)的是指針集合攒盈,那在 遍歷里修改是有效的,如果 slice 存儲(chǔ)的是值類型的集合哎榴,那么就是在 copy 它們的副本型豁,期間的修改也只是在修改這個(gè)副本僵蛛,跟原來的 slice 里的元素是沒有關(guān)系的

  • 如果 slice 作為函數(shù)的入?yún)ⅲǔOM麑?duì) slice 的操作可以影響到底層數(shù)據(jù)迎变,但是如果在函數(shù)內(nèi)部 append 數(shù)據(jù)超過了 cap充尉,導(dǎo)致重新分配底層數(shù)組,這時(shí)修改的 slice 將不再是原來入?yún)⒌哪莻€(gè) slice 了衣形。因此通常不建議在函數(shù)內(nèi)部對(duì) slice 有 append 操作驼侠,若有需要?jiǎng)t顯示的 return 這個(gè) slice

func main() {
    sl := make([]*M, 0, 0)

    sl = append(sl, &M{
        Name: "sun",
    })

    log.Println("sl 原始數(shù)據(jù):", len(sl), cap(sl))

    s2 := add(sl)
    log.Println("sl 處理后數(shù)據(jù):", len(sl), cap(sl))
    log.Println("s2 處理后數(shù)據(jù)", len(s2), cap(s2))
    for _, v := range s2 {
        log.Println(v)
    }
}

func add(m []*M) []*M {
    m = append(m, &M{
        Name: "wang1",
    }, &M{
        Name: "wang2",
    })
    return m
}

輸出:

2022/02/17 15:43:46 sl 原始數(shù)據(jù): 1 1
2022/02/17 15:43:46 sl 處理后數(shù)據(jù): 1 1
2022/02/17 15:43:46 s2 處理后數(shù)據(jù) 3 3
2022/02/17 15:43:46 &{sun}
2022/02/17 15:43:46 &{wang1}
2022/02/17 15:43:46 &{wang2}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谆吴,隨后出現(xiàn)的幾起案子倒源,更是在濱河造成了極大的恐慌,老刑警劉巖句狼,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笋熬,死亡現(xiàn)場離奇詭異,居然都是意外死亡腻菇,警方通過查閱死者的電腦和手機(jī)胳螟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芜繁,“玉大人旺隙,你說我怎么就攤上這事】チ睿” “怎么了蔬捷?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長榔袋。 經(jīng)常有香客問我周拐,道長,這世上最難降的妖魔是什么凰兑? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任妥粟,我火速辦了婚禮,結(jié)果婚禮上吏够,老公的妹妹穿的比我還像新娘勾给。我一直安慰自己,他們只是感情好锅知,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布播急。 她就那樣靜靜地躺著,像睡著了一般售睹。 火紅的嫁衣襯著肌膚如雪桩警。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天昌妹,我揣著相機(jī)與錄音捶枢,去河邊找鬼握截。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烂叔,可吹牛的內(nèi)容都是我干的谨胞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼长已,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼畜眨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起术瓮,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贰健,沒想到半個(gè)月后胞四,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伶椿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年辜伟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脊另。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡导狡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偎痛,到底是詐尸還是另有隱情旱捧,我是刑警寧澤,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布踩麦,位于F島的核電站枚赡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谓谦。R本人自食惡果不足惜贫橙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望反粥。 院中可真熱鬧卢肃,春花似錦、人聲如沸才顿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娜膘。三九已至逊脯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竣贪,已是汗流浹背军洼。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來泰國打工巩螃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匕争。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓避乏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甘桑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拍皮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

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