Go中的switch的六種使用:沒有你想象中那么簡(jiǎn)單
Go以其簡(jiǎn)潔而著稱,但并不是每個(gè)人都熟悉這種語言中switch語句的多樣性。首先,如果你對(duì)Go的switch語句還不熟悉,它可能與其他語言相比有些不同。
下面是一個(gè)簡(jiǎn)單的示例來展示它是什么樣子的:
func main() {
var i int = 1
switch i {
case 1:
fmt.Println("i is 1")
case 2:
fmt.Println("i is 2")
default:
fmt.Println("i is not 1 or 2")
}
}
Go的switch語句有一個(gè)很酷的特性,即在找到匹配項(xiàng)后就會(huì)停止執(zhí)行,不需要在每個(gè)case的末尾加上break語句。
在Go的switch語句中有兩個(gè)部分:分號(hào)前的部分是初始化器,分號(hào)后的部分是要檢查的值。
可以選擇使用兩個(gè)部分、其中一個(gè)部分或者都不使用:
switch initializer; value {}
switch initializer {}
switch value {}
switch {}
很有趣,是吧?
使用字面布爾值的switch
有時(shí)候,可能會(huì)使用一個(gè)變量的switch語句,但這里有一種不同的方法。
考慮使用一個(gè)帶有字面布爾值的switch語句。這種方法可以讓我們檢查多個(gè)條件,而不僅僅局限于一個(gè)變量的值。
func main() {
var a int = 1
var b int = 2
switch true { // <--- use true literal
case a == 1 && b == 2:
fmt.Println("a is 1 and b is 2")
case a == 3:
fmt.Println("a is 3"):
default:
fmt.Println("a is not 1 or 3")
}
}
乍一看,switch true可能似乎是多余和無意義的。
它感覺有點(diǎn)像在陳述顯而易見的事實(shí),但好消息是Go有一種更簡(jiǎn)化的處理方式,可以像這樣簡(jiǎn)化它:
switch { // <--- just remove `true`
case a == 1 && b == 2:
...
}
這種簡(jiǎn)化的方法同樣有效。
另外,switch語句也可以與false字面值一起使用,提供了一種確定哪些條件未滿足的方法。
Switch短賦值
我們經(jīng)常忽視switch語句中的初始化器部分。
但它非常有用,與if語句或for循環(huán)中的初始化器類似。它允許你聲明并賦值一個(gè)變量,然后立即使用它。
下面是一個(gè)例子來說明這一點(diǎn):
switch a := 1; a {
case 1:
fmt.Println("a is 1")
}
// similar
if a := 1; a == 1 {
fmt.Println("a is 1")
}
在這些情況下,變量a的作用域僅限于switch語句,意味著不能在外部使用a。
還記得我們可以忽略switch的兩個(gè)部分嗎?
你也可以選擇只使用初始化器部分,當(dāng)你這樣做時(shí),值部分被假定為true:
switch a := 1 {
case a == 1:
fmt.Println("a is 1")
case a == 2:
fmt.Println("a is 2")
}
到目前為止,我們已經(jīng)看到了四種組織switch語句的方式:只使用初始化器、只使用值、兩者都使用或者兩者都不使用。但我們的重點(diǎn)主要在于switch本身。
接下來,我們將深入探討case部分的作用以及如何在代碼中充分利用它。
包含多個(gè)值的case
你可以在一個(gè)case中組合多個(gè)值。這種方法可以使你的代碼更簡(jiǎn)潔易讀:
switch a := 1; a {
case 1, 2, 3: // <--
fmt.Println("a is 1, 2 or 3")
}
很多Go的新手并不知道這個(gè)功能。相反,他們可能會(huì)寫出這樣的代碼:
switch a := 1; a {
case 1:
case 2:
case 3:
fmt.Println("a is 1, 2 or 3")
}
但這種方法并不完全正確,因?yàn)閟witch在Go中的工作方式不同。
在這個(gè)例子中,打印語句只與最后一個(gè)case(case 3)相關(guān)聯(lián)。所以,如果a是1或2,什么也不會(huì)發(fā)生,因?yàn)檫@些case后面沒有指令,程序會(huì)直接跳過它們。
使用fallthrough關(guān)鍵字的case
這個(gè)關(guān)鍵字允許執(zhí)行繼續(xù)到下一個(gè)case而不檢查其條件。這與大多數(shù)語言處理switch case的方式有些不同。
下面是一個(gè)例子來展示fallthrough的工作方式:
switch a := 1; a {
case 1:
fmt.Println("a is 1")
fallthrough
case 2:
fmt.Println("Now in case 2")
default:
fmt.Println("Neither 1 nor 2")
}
輸出會(huì)是什么?
在這種情況下,當(dāng)a為1時(shí),程序首先打印“a is 1”。然后,由于fallthrough關(guān)鍵字的存在,它會(huì)立即跳轉(zhuǎn)到下一個(gè)case(case 2),而不檢查a是否實(shí)際上為2。所以,它也會(huì)打印出“Now in case 2”。
你仍然可以在case 2中使用fallthrough關(guān)鍵字,程序會(huì)繼續(xù)執(zhí)行下一個(gè)case(default),并打印“Neither 1 nor 2”。
switch a := 1; a {
case 1:
fmt.Println("a is 1")
fallthrough
case 2:
fmt.Println("Now in case 2")
fallthrough
default:
fmt.Println("Neither 1 nor 2")
}
// Output:
// a is 1
// Now in case 2
// Neither 1 nor 2
但要記住,在Go中,fallthrough關(guān)鍵字繞過了下一個(gè)case的條件檢查。因此,在switch語句的最后一個(gè)case中不使用它,因?yàn)闆]有后續(xù)的case可以過渡到。
默認(rèn)情況和其細(xì)微差別
Go中的switch語句的默認(rèn)情況類似于if語句中的else部分。
當(dāng)沒有任何其他case匹配時(shí),它將執(zhí)行默認(rèn)情況,但是在Go中,默認(rèn)情況有一些有趣的特點(diǎn):
盡管在大多數(shù)編程語言中,默認(rèn)情況通常放在末尾,但在Go中,它可以放置在switch語句的任何位置。大多數(shù)人為了清晰起見會(huì)把它放在末尾,但讓我們看看當(dāng)我們把它放在開頭時(shí)會(huì)發(fā)生什么:
switch a := 1; a {
default:
fmt.Println("Neither 1 nor 2")
case 1:
fmt.Println("a is 1")
case 2:
fmt.Println("Now in case 2")
}
在這個(gè)例子中,即使默認(rèn)情況首先出現(xiàn),它仍然被視為最后的選擇,只有在沒有其他case匹配時(shí)才會(huì)執(zhí)行。
但還有另一層可以探索。
如果我們將默認(rèn)情況與fallthrough關(guān)鍵字混合使用會(huì)怎么樣?讓我們來看看:
switch a := 3; a {
default:
fmt.Println("Neither 1 nor 2")
fallthrough
case 1:
fmt.Println("a is 1")
case 2:
fmt.Println("Now in case 2")
}
// Output:
// Neither 1 nor 2
// a is 1
在這種情況下,當(dāng)a為3時(shí),switch從默認(rèn)情況開始,打印“Neither 1 nor 2”。然后,由于fallthrough的存在,它會(huì)移動(dòng)到下一個(gè)case,打印“a is 1”。
帶有類型斷言的switch
switch語句不僅可以處理值,還可以處理類型。這在處理接口時(shí)特別有用。
類型斷言是實(shí)現(xiàn)這一功能的特性,它允許檢查接口值的類型,并根據(jù)該類型運(yùn)行不同的代碼段:
func main() {
var i interface{} = "hello"
switch v := i.(type) {
case int:
fmt.Println("i is an int and its value is", v)
case string:
fmt.Println("i is a string and its value is", v)
default:
fmt.Println("Unknown type")
}
}
在這種情況下,i是一個(gè)存儲(chǔ)字符串的接口變量。
switch語句使用i.(type)來確定i的類型,然后根據(jù)該類型選擇要執(zhí)行的case:
- 它逐個(gè)檢查每個(gè)case是否為特定類型(如int或string)。
- 在每個(gè)case中,v表示i作為該case中檢查的類型的值,因此可以像使用該類型的任何變量一樣使用v。