Go基礎系列:常量和變量

常量(Constants)和iota

常量包含不會發生更改的數據。常量的數據類型只能是boolean、number(int/float/complex)或string。html

定義方式:數據結構

const NAME [TYPE] = VALUE

TYPE基本能夠省略,由於常量都是簡單數據類型,編譯器能夠根據值推斷出它的數據類型。閉包

例如:ide

const Pi = 3.14159

常量在編譯期間被評估,所以定義的常量必須是在編譯期間就能計算出來的結果。例如調用一些運行期間的函數來生成常量的值就是錯誤的,由於在編譯期間沒法調用這些運行期間的函數。常量的值定義好後,沒法在運行期間更改,不然會報錯。函數

const c = 3+2          // 正確
const d = getNumber()  // 錯誤

常量的精度能夠隨意長,Go不會出現精度溢出的問題。且常量賦值時,若是值太長,可使用續行符\ui

const Ln2= 0.693147180559945309417232121458\
            176568075500134360255254120680009
const Log2E= 1/Ln2
const Billion = 1e9

Go中只有將超出變量精度的值賦值給變量時纔會出現溢出問題。code

能夠一次性定義多個常量:htm

const beef, two, c = "meat", 2, "veg"
const Monday, Tuesday, Wednesday = 1, 2, 3
const (
    Monday, Tuesday, Wednesday = 1, 2, 3
    Thursday, Friday, Saturday = 4, 5, 6
)

常量能夠用枚舉。定義了下面的常量後,Female就表明了數值1。blog

const (
    Unknown = 0
    Female = 1
    Male = 2
)

可使用iota實現枚舉,iota自身是builtin包中定義的一個常量,其值爲0,它用於在常量中定義序列數,從0開始增長:ip

const (
    a = iota
    b = iota
    c = iota
)

iota第一次調用時,產生數值0,在新行中再次調用iota,將自動增長1,因此上面的a=0,b=1,c=2。上面的常量枚舉能夠簡寫成等價形式:

const (
    a = iota
    b
    c
)

iota不能用於運行期間,由於它是小寫字母開頭的常量,不會被導出。下面的代碼會報錯:iota未定義

var a int = iota

iota也能夠用於表達式中,例如iota+50表示將當前的iota值加上50。

每一個常量塊(const block)結構都會重置和初始化iota的值爲0

func main() {
    const a = iota           // a=0
    const b = iota + 3       // b=3
    const c,d = iota,iota+3  // c=0,d=3
    const (
        e = iota           // e=0
        f = iota + 4       // f=5
        g                  // g=6
    )
    println(a,b,c,d,e,f,g)
}

變量

在使用變量以前,有兩個過程:聲明變量、變量賦值。聲明變量也常被稱爲"定義變量"。變量聲明後必須使用,不然會報錯。

定義變量的經常使用方式:

var identifier type

例如:

var a int
var b bool
var str string

// 或者
var (
    a int
    b bool
    str string
)

當變量聲明的時候,會作默認的賦0初始化,每種數據類型的默認賦0初始化的0值不一樣。例如int類型的0值爲數值0,float的0值爲0.0,string類型的0值爲空"",bool類型的0值爲false,數據結構的0值爲nil,struct的0值爲字段所有賦0。

變量在編譯期間就能夠獲取到它的值,但若是賦值給變量的值須要通過運行期間的計算,則須要延遲到運行期間才能獲取對應的值。

var a int = 15     // 編譯期間賦值好
var b int = 15/3   // 編譯期間賦值好
var c = getNumber() // 運行期間才賦值

聲明和賦值能夠結合:

var a int = 15
var i = 5
var b bool = false
var str string = "Hello World"

聲明和賦值結合的時候,對於簡單數據類型的值,能夠省略type部分,由於Go能夠根據值本身推斷出類型:

var a = 15
var b = false
var str = "Hello World"

var (
    a = 15
    b = false
    str = "Hello World"
    numShips = 50
    city string
)

由於要推斷數據類型,因此類型推斷操做是在運行期間完成的。

在使用推斷類型的賦值時,若是想要指定特定類型,須要顯式指定。例如整數數值推斷的類型爲int,要想讓它保存到int64中,則必須顯式指定類型:

var a int64 = 2

要推斷類型必須是聲明和賦值一塊兒的,不然沒有值,沒法根據值去推斷。例如var a是錯的。

除了上面的推斷方式,經過:=符號也能實現聲明和賦值結合,它也會根據數據類型進行推斷,連var關鍵字都省略了:

a := 50

可是:=只能在函數代碼塊內部使用,在全局做用域下使用將報錯,由於類型推斷是在運行期執行的,而全局範圍內的變量聲明部分是在編譯期間就決定好的。例如,下面的將報錯:

a := 10
func main() { println(a) }

變量聲明以後不能再次聲明(除非在不一樣的做用域),以後只能使用=進行賦值。例如,執行下面的代碼將報錯:

package main

import ("fmt")

func main(){
    x:=10
    fmt.Println("x =",x)
    x:=11
    fmt.Println("x =",x)
}

錯誤以下:

# command-line-arguments
.\test.go:8:3: no new variables on left side of :=

報錯信息很明顯,:=左邊沒有新變量。

若是仔細看上面的報錯信息,會發現no new variables是一個複數。實際上,Go容許咱們使用:=一次性聲明、賦值多個變量,並且只要左邊有任何一個新變量,語法就是正確的。

func main(){
    name,age := "longshuai",23
    fmt.Println("name:",name,"age:",age)
    
    // name從新賦值,由於有一個新變量weight
    weight,name := 90,"malongshuai"
    fmt.Println("name:",name,"weight:",weight)
}

須要注意,name第二次被:=賦值,Go第一次推斷出該變量的數據類型以後,就不容許:=再改變它的數據類型,由於只有第一次:=對name進行聲明,以後全部的:=對name都只是簡單的賦值操做。

例如,下面將報錯:

weight,name := 90,80

錯誤信息:

.\test.go:11:14: cannot use 80 (type int) as type string in assignment

另外,變量聲明以後必須使用,不然會報錯,由於Go對規範的要求很是嚴格。例如,下面定義了weight但卻沒使用:

weight,name := 90,"malongshuai"
fmt.Println("name:",name)

錯誤信息:

.\test.go:11:2: weight declared and not used

變量做用域(scope)

Go語言的做用域採用的是詞法做用域,意味着文本段定義所在位置決定了可看見的值範圍。關於詞法做用域和動態做用域,詳細內容參見:一文搞懂:詞法做用域、動態做用域、回調函數、閉包

  • 定義在函數內部的變量爲局部變量,只在函數內部可見
  • 定義在代碼塊內(如{...CODE...})的變量也是局部變量,除了代碼塊就消失
  • 定義在代碼塊外、函數外的變量爲包變量或者全局變量,它們能夠被同一個目錄下同一個包的多個文件訪問(由於Go中一個目錄下只能定義一個包,但一個包能夠分紅多個文件)
    • 若是變量的名稱以小寫字母開頭,則其它包不能訪問該變量
    • 若是變量的名稱以大寫字母開頭,則其它包能夠訪問該變量

不一樣scope的變量名能夠衝突,但建議採起名稱惟一的方式爲變量命名。

相關文章
相關標籤/搜索