<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go1.18 快訊:新增字符串 Clone API

          共 2748字,需瀏覽 6分鐘

           ·

          2021-11-05 15:12

          閱讀本文大概需要 5 分鐘。

          大家好,我是 polarisxu。

          Go 1.18 雖然還有 4 個(gè)月發(fā)布,但大部分的功能基本確定。我們可以提前知曉、熟悉。

          今天介紹的是標(biāo)準(zhǔn)庫(kù)中新增的一個(gè) API:strings.Clone()

          從名稱可以知道,這是克隆。很多其他語(yǔ)言一開始就有這樣的功能。比如 PHP 有 clone 關(guān)鍵字、__clone 魔術(shù)方法;Java 的根類 Object 有 clone 方法等。

          01 函數(shù)簽名

          該函數(shù)的定義如下(見:https://pkg.go.dev/strings@master#Clone)

          //?Clone?returns?a?fresh?copy?of?s.
          //?It?guarantees?to?make?a?copy?of?s?into?a?new?allocation,
          //?which?can?be?important?when?retaining?only?a?small?substring
          //?of?a?much?larger?string.?Using?Clone?can?help?such?programs
          //?use?less?memory.?Of?course,?since?using?Clone?makes?a?copy,
          //?overuse?of?Clone?can?make?programs?use?more?memory.
          //?Clone?should?typically?be?used?only?rarely,?and?only?when
          //?profiling?indicates?that?it?is?needed.
          //?For?strings?of?length?zero?the?string?""?will?be?returned
          //?and?no?allocation?is?made.
          func?Clone(s?string)?string

          Clone 返回 s 的新副本。它保證將 s 復(fù)制到一個(gè)新分配的副本中,當(dāng)只保留一個(gè)很大的字符串中的一個(gè)小子字符串時(shí),這一點(diǎn)很重要。使用克隆可以幫助這些程序使用更少的內(nèi)存。當(dāng)然,由于使用克隆制作拷貝,過(guò)度使用克隆會(huì)使程序使用更多內(nèi)存。通常,只有在分析表明需要克隆時(shí),才謹(jǐn)慎使用克隆。對(duì)于長(zhǎng)度為零的字符串,將返回字符串 "",不進(jìn)行內(nèi)存分配。

          02 舉例說(shuō)明

          大家可能還是迷惑,不知道有啥用。舉一個(gè)代碼例子說(shuō)明:

          package?main

          import?(
          ?"fmt"
          ?"reflect"
          ?"unsafe"
          )

          func?main()?{
          ?s?:=?"abcdefghijklmn"
          ?s1?:=?s[:4]

          ?sHeader?:=?(*reflect.StringHeader)(unsafe.Pointer(&s))
          ?s1Header?:=?(*reflect.StringHeader)(unsafe.Pointer(&s1))
          ?fmt.Println(sHeader.Len?==?s1Header.Len)
          ?fmt.Println(sHeader.Data?==?s1Header.Data)
          ??
          ??//?Output:
          ??//?false
          ??//?true
          }

          Len 不相等不需要解釋,Data 相等就值得注意。

          上面代碼,有些人可能不知道什么意思。這里涉及到 Go 中 string 類型的底層結(jié)構(gòu)。在 Go 中,string 類型的底層表示如下:

          type?string?struct?{
          ?ptr?unsafe.Pointer
          ?len?int
          }

          而 reflect.StringHeader 結(jié)構(gòu)是對(duì)字符串底層結(jié)構(gòu)的反射表示。

          在上面示例場(chǎng)景中,如果 s 很大,而之后我們只需要使用它的某個(gè)短子串,這會(huì)導(dǎo)致內(nèi)存的浪費(fèi),因?yàn)樽哟驮址?Data 部分指向相同的內(nèi)存,因此整個(gè)字符串并不會(huì)被 GC 回收。

          strings.Clone 函數(shù)就是為了解決這個(gè)問(wèn)題的:(要正常運(yùn)行下面代碼,需要按照 Go tip 版本)

          s2?:=?strings.Clone(s[:4])

          s2Header?:=?(*reflect.StringHeader)(unsafe.Pointer(&s2))
          fmt.Println(sHeader.Len?==?s2Header.Len)
          fmt.Println(sHeader.Data?==?s2Header.Data)
          //?Output:
          //?false
          //?false

          通過(guò)克隆得到 s2,從最后輸出結(jié)果看,Data 已經(jīng)不同了,原始的長(zhǎng)字符串就可以被垃圾回收了。(你也可以將傳遞給 Clone 的參數(shù)改為 s1,后面部分用 s1 和 s2 比)

          03 內(nèi)部實(shí)現(xiàn)

          知道了克隆的用途,再看看 strings.Clone 的實(shí)現(xiàn)。

          func?Clone(s?string)?string?{
          ?if?len(s)?==?0?{
          ??return?""
          ?}
          ?b?:=?make([]byte,?len(s))
          ?copy(b,?s)
          ?return?*(*string)(unsafe.Pointer(&b))
          }

          這里有兩個(gè)關(guān)鍵點(diǎn):

          • 通過(guò) copy 進(jìn)行拷貝。其實(shí)普通的 slice,也會(huì)有需要克隆的場(chǎng)景,這時(shí),需要我們手動(dòng)執(zhí)行 copy 操作。
          • return 后面的語(yǔ)句 *(*string)(unsafe.Pointer(&b)),實(shí)現(xiàn) []byte 到 string 的零內(nèi)存拷貝轉(zhuǎn)換。

          04 總結(jié)

          Go 雖然有 GC,大部分時(shí)候不需要考慮內(nèi)存問(wèn)題,但對(duì)內(nèi)存的使用,我們需要有敬畏之心,特別是大塊內(nèi)存、重復(fù)分配內(nèi)存的場(chǎng)景,我們需要知曉如何優(yōu)化,寫出真正高質(zhì)量的代碼。

          strings.Clone 的使用很簡(jiǎn)單,但希望通過(guò)本文,你在寫 Go 代碼時(shí),對(duì)類似場(chǎng)景下,slice 的正確使用有啟發(fā)(string 可以認(rèn)為是特殊的 slice)。




          往期推薦


          我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語(yǔ)言并創(chuàng)建了 Go 語(yǔ)言中文網(wǎng)!著有《Go語(yǔ)言編程之旅》、開源圖書《Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)》等。


          堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio


          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.6969成人片亚洲 | 国产18禁美女黄禁片免费网站 | 欧美性爱在线观看 | 国产视频123区 | 亚洲无码视频观看 |