2.2 Go語(yǔ)言從入門到精通:Go語(yǔ)言變量
作者:xcbeyond
瘋狂源自夢(mèng)想,技術(shù)成就輝煌!微信公眾號(hào):《程序猿技術(shù)大咖》號(hào)主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對(duì)于Java、微服務(wù)、數(shù)據(jù)庫(kù)、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。
文章目錄
1、變量的聲明
1.1 標(biāo)準(zhǔn)聲明格式
1.2 根據(jù)值自行判定變量類型
1.3 短變量聲明
1.4 批量聲明
2、變量的初始化
3、變量的多重賦值
4、匿名變量
5、變量的作用域
5.1 局部變量
5.2 全局變量
5.3 形式參數(shù)
變量來(lái)源于數(shù)學(xué),是計(jì)算機(jī)語(yǔ)言中能儲(chǔ)存計(jì)算結(jié)果或能表示值的抽象概念。
Go語(yǔ)言是靜態(tài)類型語(yǔ)言,因此變量(variable)是有明確類型的,編譯器也會(huì)檢查變量類型的正確性。
變量可以通過變量名訪問。
Go 語(yǔ)言變量名由字母、數(shù)字、下劃線組成,其中首個(gè)字符不能為數(shù)字。
1、變量的聲明
聲明變量的一般形式是使用 var 關(guān)鍵字:
var name type
其中,var 是聲明變量的關(guān)鍵字,name 是變量名,type 是變量的類型。
還可以一次聲明多個(gè)類型相同的變量:
var name1,name2,name3 type
需要注意的是,Go語(yǔ)言和許多編程語(yǔ)言不同,它在聲明變量時(shí)將變量的類型放在變量的名稱之后。這樣做的好處就是可以避免像C語(yǔ)言中那樣含糊不清的聲明形式,例如:int* a, b; 。其中只有 a 是指針而 b 不是。如果你想要這兩個(gè)變量都是指針,則需要將它們分開書寫。而在 Go 中,則可以和輕松地將它們都聲明為指針類型:
var a, b *int
當(dāng)一個(gè)變量被聲明之后,系統(tǒng)自動(dòng)賦予它該類型的零值:int 為 0,float 為 0.0,bool 為 false,string 為空字符串,指針為 nil 等。所有的內(nèi)存在 Go 中都是經(jīng)過初始化的。
示例如下:
package main
import "fmt"
func main() {
var a,b int
fmt.Println(a,b)
}
輸出結(jié)果如下:
0 0
變量的聲明有多種形式,整理歸納如下。
1.1 標(biāo)準(zhǔn)聲明格式
Go語(yǔ)言的變量聲明的標(biāo)準(zhǔn)格式如下:
var 變量名 變量類型
或
var 變量名1,變量名2 變量類型
變量聲明以關(guān)鍵字 var 開頭,后置變量類型,行尾無(wú)須分號(hào)。
如果沒有初始化,則變量默認(rèn)為零值。(零值就是變量沒有做初始化時(shí)系統(tǒng)默認(rèn)設(shè)置的值。)
var 形式的聲明語(yǔ)句往往是用于需要顯式指定變量類型地方,或者因?yàn)樽兞可院髸?huì)被重新賦值而初始值無(wú)關(guān)緊要的地方。
示例如下:
package main
import "fmt"
func main() {
// 聲明一個(gè)沒有初始化的int類型變量,默認(rèn)為零值0
var a int
fmt.Println(a)
// 聲明一個(gè)沒有初始化的bool類型變量,默認(rèn)為零值false
var b bool
fmt.Println(b)
}
輸出結(jié)果如下:
0
false
1.2 根據(jù)值自行判定變量類型
var 變量名 = 變量值
示例如下:
package main
import "fmt"
func main() {
var c = true
fmt.Println(c)
}
輸出結(jié)果如下:
true
1.3 短變量聲明
在函數(shù)中,一種稱為短變量聲明的可選形式可以用來(lái)聲明和初始化局部變量。格式如下:
變量名 := 變量值
這里省略了關(guān)鍵字var,變量名的類型由變量值的類型決定,變量值可以是任何函數(shù)或表達(dá)式計(jì)算的結(jié)果值。
因其短小、靈活,故而在局部變量的聲明和初始化中主要使用。
短變量聲明有以下注意點(diǎn):
定義變量,同時(shí)顯式初始化。
不能直接提供數(shù)據(jù)類型。
只能用在函數(shù)內(nèi)部。
:=表示聲明,而=表示賦值。
:=左側(cè)如果是已聲明的變量,就會(huì)產(chǎn)生編譯錯(cuò)誤。如:
var intVal int
intVal := 1 // 會(huì)產(chǎn)生編譯錯(cuò)誤
1
2
示例如下:
package main
import "fmt"
func main() {
// 短變量聲明
d := "xcbeyond"
fmt.Println(d)
}
輸出結(jié)果如下:
xcbeyond
1.4 批量聲明
覺得每行都用 var 聲明變量比較煩瑣?沒關(guān)系,還有一種為懶人提供的定義變量的方法:
var (
a int
b string
c float64
)
使用關(guān)鍵字 var 和括號(hào),可以將一組變量定義放在一起。
示例如下:
package main
import "fmt"
func main() {
// 批量聲明
var (
e int
f string
g float64
)
fmt.Println(e,f,g)
}
輸出結(jié)果如下:
0 0
2、變量的初始化
變量初始化標(biāo)準(zhǔn)格式如下:
var 變量名 類型 = 變量值
如:
var i int = 100
i為變量名,類型為int,i的初始值為100。
上面代碼中,100 和 int 同為 int 類型,int 可以認(rèn)為是冗余信息,因此可以進(jìn)一步簡(jiǎn)化初始化的寫法。
在標(biāo)準(zhǔn)格式的基礎(chǔ)上,將 類型int省略后,編譯器會(huì)嘗試根據(jù)等號(hào)右邊的變量值推導(dǎo)出變量的類型。如:
var i = 100
短變量聲明并初始化,如:
i := 100
這是Go語(yǔ)言的推導(dǎo)聲明寫法,編譯器會(huì)自動(dòng)根據(jù)右值類型推斷出左值的對(duì)應(yīng)類型。
3、變量的多重賦值
賦值是用來(lái)更新變量所指的值,它最簡(jiǎn)單的形式由賦值符=,以及符號(hào)左邊的變量和右邊的表達(dá)式組成。
x = 1
person.name = "xcbeyond"
count[x] = count[x] * 5
另一種形式的賦值是多重賦值,它允許幾個(gè)變量一次性被賦值。
在Go語(yǔ)言語(yǔ)法中,變量初始化和變量賦值是兩個(gè)不同的概念,Go語(yǔ)言的變量賦值與其他語(yǔ)言一樣,但是Go語(yǔ)言提供了其他程序員期待已久的多重賦值功能,可以實(shí)現(xiàn)變量交換。多重賦值讓Go語(yǔ)言比其他語(yǔ)言減少了代碼量。
以簡(jiǎn)單的算法交換變量為例,傳統(tǒng)寫法如下所示:
var a int = 10
var b int = 20
var tmp int
tmp = a
a = b
b = t
fmt.Println(a, b)
新定義的變量tmp是需要內(nèi)存的,于是有人設(shè)計(jì)了新的算法來(lái)取代中間變量,其中一種寫法如下所示:
var a int = 10
var b int = 20
a = a ^ b
b = b ^ a
a = a ^ b
fmt.Println(a, b)
Go語(yǔ)言有了多重賦值功能,則簡(jiǎn)單寫法如下所示:
var a int = 10
var b int = 20
b, a = a, b
fmt.Println(a, b)
從以上例子來(lái)看,Go語(yǔ)言的寫法明顯簡(jiǎn)潔了許多,需要注意的是,多重賦值時(shí),左值和右值按照從左到右的順序賦值。這種方法在錯(cuò)誤處理和函數(shù)當(dāng)中會(huì)大量使用。
4、匿名變量
在編碼過程中,可能會(huì)遇到?jīng)]有名稱的變量、類型或方法。雖然這不是必須的,但有時(shí)候這樣做可以極大地增強(qiáng)代碼的靈活性,這些變量被統(tǒng)稱為匿名變量。
匿名變量的特點(diǎn)是一個(gè)下畫線_,_本身就是一個(gè)特殊的標(biāo)識(shí)符,被稱為空白標(biāo)識(shí)符。它可以像其他標(biāo)識(shí)符那樣用于變量的聲明或賦值(任何類型都可以賦值給它),但任何賦給這個(gè)標(biāo)識(shí)符的值都將被拋棄,因此這些值不能在后續(xù)的代碼中使用,也不可以使用這個(gè)標(biāo)識(shí)符作為變量對(duì)其它變量進(jìn)行賦值或運(yùn)算。使用匿名變量時(shí),只需要在變量聲明的地方使用下畫線替換即可。
例如,我們?cè)谑褂脗鹘y(tǒng)的強(qiáng)類型語(yǔ)言編程時(shí),經(jīng)常會(huì)出現(xiàn)這種情況,即在調(diào)用函數(shù)時(shí)為了獲取一個(gè)值,卻因?yàn)樵摵瘮?shù)返回多個(gè)值而不得不定義一堆沒用的變量。在Go中這種情況可以通過結(jié)合使用多重返回和匿名變量來(lái)避免這種丑陋的寫法,讓代碼看起來(lái)更加優(yōu)雅。
假設(shè)GetName()函數(shù)的定義如下,它返回3個(gè)值,分別為firstName、lastName和nickName,若只想獲得nickName,則可以用如下方式編寫:
package main
import "fmt"
func main() {
// 匿名變量
firstName, _, _ := getName()
_, lastName, _ := getName()
_, _, nickName := getName()
fmt.Println(firstName, lastName, nickName)
}
func getName() (firstName, lastName, nickName string) {
return "X", "C", "xcbeyond"
}
輸出結(jié)果如下:
X C xcbeyond
1
這種用法可以讓代碼非常清晰,基本上屏蔽掉了可能混淆代碼閱讀者視線的內(nèi)容,從而大幅降低溝通的復(fù)雜度和代碼維護(hù)的難度。
匿名變量不占用內(nèi)存空間,不會(huì)分配內(nèi)存。匿名變量與匿名變量之間也不會(huì)因?yàn)槎啻温暶鞫鵁o(wú)法使用。
5、變量的作用域
一個(gè)變量(常量、類型或函數(shù))在程序中都有一定的作用范圍,稱之為作用域。
了解變量的作用域?qū)ξ覀儗W(xué)習(xí)Go語(yǔ)言來(lái)說是比較重要的,因?yàn)镚o語(yǔ)言會(huì)在編譯時(shí)檢查每個(gè)變量是否使用過,一旦出現(xiàn)未使用的變量,就會(huì)報(bào)編譯錯(cuò)誤。如果不能理解變量的作用域,就有可能會(huì)帶來(lái)一些不明所以的編譯錯(cuò)誤。
根據(jù)變量定義位置的不同,可以分為以下三個(gè)類型:
局部變量:函數(shù)內(nèi)定義的變量。
全局變量:函數(shù)外定義的變量。
形式參數(shù):函數(shù)定義中的變量。
下面就來(lái)分別介紹一下。
5.1 局部變量
在函數(shù)體內(nèi)聲明的變量稱之為局部變量,它們的作用域只在函數(shù)體內(nèi),函數(shù)的參數(shù)和返回值變量都屬于局部變量。
局部變量不是一直存在的,它只在定義它的函數(shù)被調(diào)用后存在,函數(shù)調(diào)用結(jié)束后這個(gè)局部變量就會(huì)被銷毀。
main()函數(shù)中使用到了局部變量a、b、c,示例如下:
package main
import "fmt"
func main() {
// 聲明局部變量a和b并賦值
var a int = 3
var b int = 4
// 聲明局部變量c.并計(jì)算a和b的和
c := a + b
fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
輸出結(jié)果如下:
a = 3, b = 4, c = 7
1
5.2 全局變量
在函數(shù)體外聲明的變量稱之為全局變量,全局變量只需要在一個(gè)源文件中定義,就可以在所有源文件中使用,當(dāng)然,不包含這個(gè)全局變量的源文件需要使用“import”關(guān)鍵字引入全局變量所在的源文件之后才能使用這個(gè)全局變量。
全局變量聲明必須以var關(guān)鍵字定義,如果想要在外部包中使用全局變量的首字母必須大寫。
定義全局變量c,示例如下:
package main
import "fmt"
// 聲明全局變量
var c int
func main() {
//聲明局部變量
var a, b int
//初始化參數(shù)
a = 3
b = 4
c = a + b
fmt.Printf("a = %d, b = %d, c = %d\n", a, b, c)
}
輸出結(jié)果如下:
a = 3, b = 4, c = 7
1
Go語(yǔ)言程序中全局變量與局部變量名稱可以相同,但是函數(shù)體內(nèi)的局部變量會(huì)被優(yōu)先考慮。
5.3 形式參數(shù)
在定義函數(shù)時(shí),函數(shù)名后面括號(hào)中的變量叫做形式參數(shù)(簡(jiǎn)稱形參)。形式參數(shù)只在函數(shù)調(diào)用時(shí)才會(huì)生效,函數(shù)調(diào)用結(jié)束后就會(huì)被銷毀,在函數(shù)未被調(diào)用時(shí),函數(shù)的形參并不占用實(shí)際的存儲(chǔ)單元,也沒有實(shí)際值。
形式參數(shù)會(huì)作為函數(shù)的局部變量來(lái)使用。
函數(shù)sum(a, b int)定義了形式參數(shù)a、b,示例如下:
package main
import "fmt"
func main() {
sum := sum(1,3)
fmt.Println(sum)
}
// 兩數(shù)求和
func sum(a, b int) int{
num := a + b
return num
}
輸出結(jié)果如下:
4