<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>

          Go愛好者周刊題解:關(guān)于 len 函數(shù)的問題

          共 2888字,需瀏覽 6分鐘

           ·

          2021-07-31 20:41

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

          大家好,我是 polarisxu。

          Go語言愛好者周刊第 104 期有一道題目,以下代碼輸出什么:

          package main

          func main() {
            var x *struct {
              s [][32]byte
            }
            
            println(len(x.s[99]))
          }

          答題結(jié)果如下:

          正確率只有 16%。

          本文就講解下為什么結(jié)果是 32。

          01 解析題目

          先剖析下這段代碼,x 變量:

          var x *struct {
            s [][32]byte
          }

          注意這里不是定義一個結(jié)構(gòu)體類型,而是定義一個結(jié)構(gòu)體類型指針變量,即 x 是一個指針,指針類型是一個匿名結(jié)構(gòu)體。很顯然,x 的值是 nil,因為沒有初始化,可以打印證實這一點。

          package main

          import "fmt"

          func main() {
           var x *struct {
            s [][32]byte
           }

           fmt.Printf("x.Type = %T; x.Value= %v\n", x, x)
          }

          輸出:

          x.Type = *struct { s [][32]uint8 }; x.Value= <nil>

          這也是為什么 48% 的人選擇 A (panic) 的原因,畢竟 x 是 nil,panic 很自然的。比如這樣就會 panic:

          println(x.s)
          // panic: runtime error: invalid memory address or nil pointer dereference

          相應(yīng)的,fmt.Println(x.s[99]) 也會 panic。但為什么 len(x.s[99]) 就不 panic 了呢?所以得從 len 入手一探究竟。

          02 len 詳解

          len 函數(shù)是一個內(nèi)置類型,什么意思?就是由編譯器實現(xiàn)的。它的參數(shù)可以接收多種類型,有泛型的味道。

          func len(v Type) int

          關(guān)于它的說明,標準庫文檔有說明:

          內(nèi)建函數(shù) len 返回 v 的長度,這取決于具體類型:

          • 數(shù)組:v 中元素的數(shù)量
          • 數(shù)組指針:*v 中元素的數(shù)量(v 為 nil 時 panic)
          • 切片、map:v 中元素的數(shù)量;若 v 為nil,len(v) 即為零
          • 字符串:v 中字節(jié)的數(shù)量
          • 通道:通道緩存中隊列(未讀取)元素的數(shù)量;若 v 為 nil,len(v) 即為零

          光這個解釋,還不夠全面,len 函數(shù)還有其他一些特殊的點。這要看 Go 語言規(guī)范。

          在規(guī)范中,有一節(jié)是關(guān)于 len 和 cap 的[1]。有如下幾個要點:

          • 返回結(jié)果總是 int;
          • 返回結(jié)果有可能是常量;
          • 有時對函數(shù)參數(shù)不求值,即編譯期確定返回值;

          2、3 點解釋下。(規(guī)范中有說明)

          如果 len 或 cap 的函數(shù)參數(shù) v 是字符串常量,則返回值是一個常量。

          如果 v 的類型是數(shù)組或指向數(shù)組的指針,且表達式 v 沒有包含 channel 接收或(非常量)函數(shù)調(diào)用,則返回值也是一個常量。這種情況下,不會對 v 進行求值(即編譯期就能確定)。否則返回值不是常量,且會對 v 進行求值(即得運行時確定)。

          這一點是這道題的關(guān)鍵。

          首先,x.s[99] 的類型是 [32]byte,它是一個數(shù)組,且表達式 x.s[99] 沒有包含 channel 接收也不是函數(shù)調(diào)用,因此不會對  x.s[99] 進行求值,不求值自然不會 panic(想不明白?可以想成沒有解引用操作)。也就是說,編譯器能夠在編譯階段分析出 x.s[99] 的類型是 [32]byte,且不需要對 x.s[99] 求值,因此直接返回數(shù)組的長度,即 32。

          03 其他類似情況

          類似這樣不求值的情況還有沒有?還真有。比如下面的代碼:

          var testdata *struct {
            a *[7]int
          }
          for i, _ := range testdata.a {
            fmt.Println(i)
          }

          同樣不會 panic,原理和上面的類似,在 Go 語言規(guī)范有說明[2]。

          "range" 子句中右側(cè)的表達式被稱為 range 表達式 ,它可以是數(shù)組、數(shù)組的指針、切片、字符串、map或是允許接收操作 的 channel。range 表達式會在開始此循環(huán)前被求值一次,但有一個例外:當存在最多一個迭代變量且 len(x) 是常量時,range 表達式是不被求值的。

          所以上面代碼中 testdata.a 不會被求值,因為 len(testdata.a) 是常量。

          但如果改為這樣:

          var testdata *struct {
            a *[7]int
          }
          for i, j := range testdata.a {
            fmt.Println(i, j)
          }

          就會 panic。

          04 總結(jié)

          通過這么一道「詭異」的面試題,希望你能夠?qū)?len 有更深的理解,也希望你能夠重視 Go 語言規(guī)范,多留意一些細節(jié),同時學會如何尋找問題的答案。

          參考資料

          [1]

          關(guān)于 len 和 cap 的: https://hao.studygolang.com/golang_spec.html#id221

          [2]

          在 Go 語言規(guī)范有說明: https://hao.studygolang.com/golang_spec.html#id355




          往期推薦
          福利

          我為大家整理了一份從入門到進階的Go學習資料禮包,包含學習建議:入門看什么,進階看什么。關(guān)注公眾號 「polarisxu」,回復(fù) ebook 獲??;還可以回復(fù)「進群」,和數(shù)萬 Gopher 交流學習。

          瀏覽 45
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  九九热这里只有精品12 | 蜜桃91精品秘 入口内裤 | 91精品综合久久久久久五月天 | 一区二区电影网 | 国产三级午夜理伦三级 |