Go語言是靜態類型語言,因此變量(variable)是有明確類型的,編譯器也會檢查變量類型的正確性。
我們從計算機系統的角度來講,變量就是一段或者多段內存,用于存儲數據
1.1 標準格式
var 變量名 變量類型
1
變量聲明以關鍵字var開頭,變量類型后置,行尾無須分號
舉個例子
//聲明了一個名為age的變量,類型為int
var age int
1
2
如果你學過C語言,就會體會到這樣聲明的好處,比如C語言這樣聲明:int* a, b ,那么只有a是指針,b不是,這樣會使人迷惑,如果想要兩個變量都為指針,需要這樣定義:int *a,*b。
在go語言中,我們使用這樣的聲明方式:var a,b *int,就可以輕松的將a,b都聲明為指針。
變量的命名規則遵循駝峰命名法,即首個單詞小寫,每個新單詞的首字母大寫,例如: startDate
1.2 基本類型
計算機中數據存儲的最小單位為bit(位),0或者1
byte:計算機中數據的基本單元,1字節=8bit,數據在計算機中存儲或者計算,至少為1個字節
- bool
- string
- int(隨系統,一般是占用4個字節)、int8(占一個字節)、int16(占兩個字節)、int32(占4個字節)、int64(占8個字節)
- uint(無符號整數)、uint8、uint16、uint32、uint64、uintptr
- byte // uint8 的別名
- rune // int32 的別名 代表一個 Unicode 碼
- float32、float64
- complex64、complex128
有符號和無符號的區別:int8 范圍 -128-127,uint8 范圍:0-255
當一個變量被聲明之后,系統自動賦予它該類型的零值:
int 為 0,float 為 0.0,bool 為 false,string 為空字符串,指針為 nil
所有的內存在 Go 中都是經過初始化的。
func main() {var age intage = 23fmt.Println(age)
}
1.3 不指明變量類型
//設置游戲中角色的初始等級為1
var level = 1;
1
2
像上面這種聲明變量的方式,并沒有指明類型,Go語言中,在編譯時會自動推導類型
我們可以使用
fmt.Printf("%T", level)
1
進行類型輸出。
func main() {//年齡為1 ,進行自動類型推斷var age = 1fmt.Printf("%T", age)}
1.4 批量格式
覺得每行都用 var 聲明變量比較煩瑣?Go語言提供了批量聲明的方式
func main() {// 批量類型聲明var (age int //年齡name string // 姓名length float32 //長度)age = 19name = "lct"length = 19.12fmt.Printf("age=%d,name=%s,length=%f", age, name, length)
}
1.5
我們可以省略var關鍵字,這樣寫起來更加便捷
//i是變量名 1 是值(或者表達式)
i := 1
1
2
上面講過,如果不指明類型,直接賦值,Go會自動推導類型
使用簡短格式有以下限制:
- 定義變量,同時顯式初始化
- 不能提供數據類型
- 只能用在函數內部
func main() {age := 10fmt.Printf("%T", age)
}
簡短變量聲明被廣泛用于大部分的局部變量的聲明和初始化,var 形式的聲明語句往往用于需要顯式指定變量類型的地方
2. 初始化變量
//兩種初始化方式var length float32 = 13.23age := 10
以下的代碼會出錯:
package mainfunc main() {var level int = 1// 再次聲明并賦值 會報錯 no new variables on left side of := (左邊的變量已經被聲明了,不能重復聲明)level := 1
}
但是有特例
比如:net.Dial 提供按指定協議和地址發起網絡連接,這個函數有兩個返回值,一個是連接對象(conn),一個是錯誤對象(err)
正常的寫法:
package mainimport ("fmt""net"
)
func main() {var conn net.Connvar err errorconn, err = net.Dial("tcp", "127.0.0.1:8080")fmt.Println(conn)fmt.Println(err)
}
短變量的寫法:
func main() {conn, err := net.Dial("tcp", "127.0.0.1:8080")if err != nil {fmt.Println(err)}fmt.Println(conn)
}
在多個短變量聲明和賦值中,至少有一個新聲明的變量出現在左值中,即便其他變量名可能是重復聲明的,編譯器也不會報錯
3. 小demo
變量交換,比如a=100,b=200,交換之后 a=200,b=100
如果是你,你會怎么樣進行實現呢?
第一種
func main() {var a int = 100var b int = 200var temp inttemp = aa = bb = tempfmt.Println("a=", a, "b=", b)
}
第二種
func main() {var a int = 100var b int = 200//異或操作a = a ^ bb = a ^ ba = a ^ bfmt.Println("a=", a, "b=", b)
}
第三種
func main() {var a int = 100var b int = 200a, b = b, afmt.Println("a=", a, "b=", b)
}
- 匿名變量
使用多重賦值時,如果不需要在左值中接受變量,可以使用匿名變量
比如上面的例子:
//conn, err := net.Dial("tcp", "127.0.0.1:8080")//如果不想接受error的值,可以用 _ 來代替conn, _ := net.Dial("tcp", "127.0.0.1:8080")
匿名變量以“_”下劃線表示
匿名變量不占用命名空間,也不會分配內存。匿名變量可以重復聲明使用
“_”本身就是一個特殊的標識符,被稱為空白標識符。它可以像其他標識符那樣用于變量的聲明或賦值(任何類型都可以賦值給它),但任何賦給這個標識符的值都將被拋棄,因此這些值不能在后續的代碼中使用,也不可以使用這個標識符作為變量對其它變量進行賦值或運算。
5. 作用域
一個變量(常量、類型或函數)在程序中都有一定的作用范圍,稱之為作用域。
了解變量的作用域對我們學習Go語言來說是比較重要的,因為Go語言(靜態語言)會在編譯時檢查每個變量是否使用過,一旦出現未使用的變量,就會報編譯錯誤。
如果不能理解變量的作用域,就有可能會帶來一些不明所以的編譯錯誤。
根據變量定義位置的不同,可以分為以下三個類型:
- 函數內定義的變量稱為局部變量
- 函數外定義的變量稱為全局變量
- 函數定義中的變量稱為形式參數
5.1 局部變量
在函數體內聲明的變量稱之為局部變量,它們的作用域只在函數體內,函數的參數和返回值變量都屬于局部變量。
局部變量不是一直存在的,它只在定義它的函數被調用后存在,函數調用結束后這個局部變量就會被銷毀。
package main
import ("fmt"
)
func main() {//聲明局部變量 a 和 b 并賦值var a int = 3var b int = 4//聲明局部變量 c 并計算 a 和 b 的和c := a + bfmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
5.2 全局變量
在函數體外聲明的變量稱之為全局變量,全局變量只需要在一個源文件中定義,就可以在所有源文件中使用,當然,不包含這個全局變量的源文件需要使用“import”關鍵字引入全局變量所在的源文件之后才能使用這個全局變量。
全局變量聲明必須以 var 關鍵字開頭,如果想要在外部包中使用全局變量的首字母必須大寫。
package main
import "fmt"
//聲明全局變量
var c int
func main() {//聲明局部變量var a, b int//初始化參數a = 3b = 4c = a + bfmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
Go語言程序中全局變量與局部變量名稱可以相同,但是函數體內的局部變量會被優先考慮。
var name string = "xiaoming"func main() {name := "xiaohong"fmt.Println(name) //xiaohong}
5.3 形式參數
在定義函數時函數名后面括號中的變量叫做形式參數(簡稱形參)。形式參數只在函數調用時才會生效,函數調用結束后就會被銷毀,在函數未被調用時,函數的形參并不占用實際的存儲單元,也沒有實際值。
形式參數會作為函數的局部變量來使用。
func main() {var a, b inta = 10b = 20fmt.Println("main 中的 a:", a, " b:", b)c := sum(a, b)fmt.Println("c:", c)
}func sum(a, b int) int {fmt.Println("sum中的a:", a, " b:", b)return a + b
}//main 中的 a: 10 b: 20
//sum中的a: 10 b: 20
//c: 30