Go語言中fmt.Println(true)的結果一定是true麼?

coding進階發表於2022-02-17

背景

Honeycomb的首席開釋出道者Jessica在Twitter上發了一條狀態:

fmt.Println("What is truth?", true)

can output:

What is truth? false

意思是下面程式碼的執行結果可能是What is truth? false

fmt.Println("What is truth?", true)

大家可以先想想什麼情況下會出現這樣的結果。

解析

我們來看下面這段程式碼:

// identifier.go
package main

import "fmt"

func main() {
    true := false
    fmt.Println(true)
}

大家覺得這段程式碼是會編譯報錯呢,還是正常執行?

實際執行結果是列印false,並不會編譯報錯。

因此本文開頭的程式碼fmt.Println("What is truth?", true)是可能列印What is truth? false的。

有的同學可能好奇了?為什麼會這樣呢?true不是Go語言的關鍵字麼,為什麼還可以定義識別符號為true 的變數?

答案是:true 並不是Go語言的關鍵字,Go語言目前只有25個關鍵字,如下所示:

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

這些關鍵字是不可以用來作為Go語言的識別符號的。true預宣告識別符號,是可以作為Go語言的識別符號的,官方說明如下:

Predeclared identifiers

The following identifiers are implicitly declared in the universe block:

Types:
    bool byte complex64 complex128 error float32 float64
    int int8 int16 int32 int64 rune string
    uint uint8 uint16 uint32 uint64 uintptr

Constants:
    true false iota

Zero value:
    nil

Functions:
    append cap close complex copy delete imag len
    make new panic print println real recover

因此true := false這樣的程式碼在Go語言是可以正常編譯通過的,並且go vet也不會檢測出任何潛在錯誤。

不僅僅是true,預宣告識別符號裡的所有識別符號都可以用來作為全域性變數和區域性變數的識別符號,比如下面的程式碼:

// identifier2.go
package main

import "fmt"

var nil = 100

var false = true

func main() {
    true := false
    fmt.Println(true, false, nil)
}

大家可以想想輸出結果是什麼?

  • A: true false nil
  • B: true false 100
  • C: true true 100
  • D: false true 100
  • E: false true nil

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

總結

Go語言的這個特性也引起了很多爭議,正如Go的錯誤處理一樣。

我們作為使用者,需要注意:Go不允許把關鍵字作為識別符號,其它都可以作為識別符號

開源地址

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

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

個人網站:Jincheng's Blog

知乎:無忌

References

相關文章