1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Go1.17 新特性之切片變數(shù)組

        共 4124字,需瀏覽 9分鐘

         ·

        2021-06-22 10:01

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

        大家好,我是 polarisxu。

        按計劃,Go 1.17 會在 2021 年 8 月份發(fā)布(目前已經(jīng)發(fā)布了 Beta1 版本)。目前,1.17 相關(guān)的功能已經(jīng)開發(fā)差不多了,上次介紹了測試順序隨機的問題,今天介紹 1.17 中的另一個新功能:切片顯式地轉(zhuǎn)換成數(shù)組指針。

        溫馨提示,如果要試驗該功能,需要升級到 1.17 Beta1 版本。另外一個主意事項就是如果在有 go.mod 的目錄中試驗,確保其中的版本改為 1.17,否則會報錯:conversion of slices to array pointers only supported as of -lang=go1.17

        01 數(shù)組轉(zhuǎn)切片

        介紹新功能之前,我們先看看在 Go 中如何將數(shù)組轉(zhuǎn)為切片。(當然,數(shù)組指針也是 OK 的)

        一般地,通過 slice 表達式(slice expressions)可以從一個數(shù)組得到一個切片。

        a[low : high : max]

        其中,max 可以省略。比如:

        a := [5]int{12345}
        s := a[1:4]

        s 就是一個切片。

        02 切片轉(zhuǎn)數(shù)組指針

        先了解下,為什么會有這樣的需求。

        該需求來自這個 issue:https://github.com/golang/go/issues/395。rogpeppe 提到,很多時候,函數(shù)接收一個 slice 參數(shù),但如果使用數(shù)組指針,則允許編譯器在編譯時檢查常量索引。比如這樣的情況:

        func foo(a []int) int {
            return a[0] + a[1] + a[2] + a[3];
        }

        能夠編譯期進行索引檢查。比如這樣(當然,最后實現(xiàn)不是這樣的):

        func foo(a []int) int {
            b := a.[0:4];
            return b[0] + b[1] + b[2] + b[3];
        }

        此外,有時候我們通過數(shù)組得到切片,但有時候我們直接創(chuàng)建切片,底層數(shù)組是匿名的。如果我們想要獲得底層數(shù)組怎么辦?將切片轉(zhuǎn)為數(shù)組指針可以實現(xiàn)這個需求。

        看看具體的例子,以下來自 Go 語言規(guī)范(針對 Go1.17 這個語言特性新增):

        s := make([]byte24)
        s0 := (*[0]byte)(s)      // s0 != nil
        s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
        s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)

        var t []string
        t0 := (*[0]string)(t)    // t0 == nil
        t1 := (*[1]string)(t)    // panics: len([1]string) > len(s)

        幾個注意的點:

        • 當切片的長度小于數(shù)組長度(len)時會 panic。所以上面例子中,s4 和 t1 發(fā)生了 panic
        • 將一個非空切片轉(zhuǎn)為 0 長度的數(shù)組,得到的指針不是 nil(如 s0);但將一個空切片轉(zhuǎn)為 0 長度的數(shù)組,得到的指針是 nil(如 t0);
        • 多次轉(zhuǎn)換,并不會創(chuàng)建多個數(shù)組(因為得到的是底層數(shù)組),這從 &s2[0] == &s[0] 可以看出;

        所以,總結(jié)一下就是,將切片轉(zhuǎn)換為數(shù)組指針,產(chǎn)生指向切片的底層數(shù)組的指針。如果切片的長度小于數(shù)組的長度,則會發(fā)生運行時 panic。

        不過針對 panic,目前沒法做斷言檢查。只能通過 if 判斷了。

        03 reflect 注意事項

        針對語言這個改動,reflect 包中的 Type 接口有一個方法:ConvertibleTo。之前的說明是這樣的:

        // ConvertibleTo reports whether a value of the type is convertible to type u.
        ConvertibleTo(u Type) bool

        1.17 是這樣的:

        // ConvertibleTo reports whether a value of the type is convertible to type u.
        // Even if ConvertibleTo returns true, the conversion may still panic.
        // For example, a slice of type []T is convertible to *[N]T,
        // but the conversion will panic if its length is less than N.
        ConvertibleTo(u Type) bool

        因為切片轉(zhuǎn)為數(shù)組指針可能會 panic,所以才加了這么一句文檔說明。

        因此,如果通過反射轉(zhuǎn)換做類型轉(zhuǎn)換,雖然通過 ConvertibleTo 判斷是可轉(zhuǎn)換的,但調(diào)用 Convert 方法依然可能 panic。這點需要特別注意下。

        04 小結(jié)

        這個語言改變,大部分時候可能用不到。但有些場景可以做到不需要內(nèi)存拷貝(copy),比如標準庫中有一個例子:

        // https://docs.studygolang.com/src/crypto/sha256/sha256.go?s=5787:5834#L252
        func Sum224(data []byte) (sum224 [Size224]byte) {
         var d digest
         d.is224 = true
         d.Reset()
         d.Write(data)
         sum := d.checkSum()
         copy(sum224[:], sum[:Size224])
         return
        }

        官方計劃修改為:

        func Sum224(data []byte) [Size224]byte {
         var d digest
         d.is224 = true
         d.Reset()
         d.Write(data)
         sum := d.checkSum()
         ap := (*[Size224]byte)(sum[:Size224])
         return *ap
        }

        注意其中的區(qū)別。

        但這里 bradfitz 在修改時,發(fā)現(xiàn),為什么一定要轉(zhuǎn)為數(shù)組指針,能否直接轉(zhuǎn)為數(shù)組,畢竟,在 Go 中使用數(shù)組的話,不太常用數(shù)組指針。于是 bradfitz 給出了另一個提案:https://github.com/golang/go/issues/46505,即 allow conversion from slice to array。目前該提案是否接受,還沒有結(jié)論。




        往期推薦


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


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


        瀏覽 38
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            嬷嬷打开双腿揉花蒂 | 婷婷久久青草热一区二区 | 男女肉粗暴进来 | 亚洲无码在线免费观看视频 | 章子怡大尺度做爰未删减 | 成人无码一区二区三区 | 大香蕉国产在线看 | 日韩在线免费视频 | 操操操操操操操 | 久久伊人视频 |