Go Quiz: 從Go面試題看變數的零值和初始化賦值的注意事項

coding進階發表於2022-05-12

背景

Google工程師Valentin Deleplace出了1道關於變數初始化的題目,本來以為很簡單,沒想到回答正確率不到30%,拿出來和大家分享下。

題目

// quiz.go
package main

import "fmt"

func main() {
    var a *int
    *a = 5.0
    fmt.Println(*a)
}
  • A: 5
  • B: 5.0
  • C: panic
  • D: 編譯錯誤

解析

這道題主要考察2個知識點:

  • 變數零值。題目中a是一個指標型別的變數,var a *int這行程式碼沒有對變數a初始化賦值,所以變數a的值是零值,指標的零值是nil,所以a的值是nil
  • 變數初始化賦值。如果對int型別的變數賦值為浮點數5.0是合法的,因為5.0是untyped float constant,是可以在不損失精度的情況下轉換為5的。如果是賦值為5.1那就非法了,因為要損失小數點後面的精度,編譯報錯如下:

    ./quiz1.go:8:7: cannot use 5.1 (untyped float constant) as int value in assignment (truncated)

所以本題答案是C,編譯的時候不會報錯,但是執行的時候因為a 的值是nil,對nil*操作就會引發panic,具體panic內容為:panic: runtime error: invalid memory address or nil pointer dereference

思考題

題目1:

// quiz1.go
package main

import "fmt"

func main() {
    var a *int = new(int)
    *a = 5.0
    fmt.Println(*a)
}

題目2:

// quiz2.go
package main

import "fmt"

func main() {
    var a *int = new(int)
    var b float32 = 5.0
    *a = b
    fmt.Println(*a)
}

題目3:

// quiz3.go
package main

import "fmt"

func main() {
    var a *int = new(int)
    *a = 5.1
    fmt.Println(*a)
}

想知道答案的可以給公眾號傳送訊息init獲取答案。

總結

Go語言裡不同型別的變數的零值不一樣,給大家總結了各個型別的變數的零值:

  • 數值:所有數值型別的零值都是0

    • 整數,零值是0。byte, rune, uintptr也是整數型別,所以零值也是0。
    • 浮點數,零值是0
    • 複數,零值是0+0i
    • 整數型別的變數是可以用untyped float constant進行賦值的,只要不損失精度即可。
  • bool,零值是false
  • 字串,零值是空串""
  • 指標:var a *int,零值是nil

    num := 100
    var a * int = &num
  • 切片:var a []int,零值是nil

    var a []int = []int{1,2}
    list := [6]int{1,2} //size為6的陣列,前面2個元素是1和2,後面的是預設值0
  • map:var a map[string] int,零值是nil

    dict := map[string] int{"a":1, "b":2}
  • 函式:var a func(string) int,零值是nil

    function := func(str string) string {
      return str
    }
    result := function("hello fans")
    fmt.Println("result=", result)
  • 結構體: var instance Struct,結構體裡每個field的零值是對應型別的零值

    type Circle struct {
      redius float64
    }
    
    var c1 Circle
    c1.radius = 10.00
  • channel:var a chan int,通道channel,零值是nil

    var a chan int = make(chan int)
    var b = make(chan string)
    c := make(chan bool)
  • 介面:var a interface_type,介面interface,零值是nil

    type Animal interface {
      speak()
    }
    
    type Cat struct {
      name string
      age int
    }
    
    func(cat Cat) speak() {
      fmt.Println("miao...")
    }
    
    // 定義一個介面變數a
    var a Animal = Cat{"gaffe", 1}
    a.speak() // miao...

開源地址

文章和示例程式碼開源在GitHub: Go語言初級、中級和高階教程

公眾號:coding進階。關注公眾號可以獲取最新Go面試題和技術棧。

個人網站:Jincheng's Blog

知乎:無忌

References

相關文章