Go中的switch的六种使用:没有你想象中那么简单
创始人
2025-07-08 01:20:05
0

Go以其简洁而著称,但并不是每个人都熟悉这种语言中switch语句的多样性。首先,如果你对Go的switch语句还不熟悉,它可能与其他语言相比有些不同。

下面是一个简单的示例来展示它是什么样子的:

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语句有一个很酷的特性,即在找到匹配项后就会停止执行,不需要在每个case的末尾加上break语句。

在Go的switch语句中有两个部分:分号前的部分是初始化器,分号后的部分是要检查的值。

可以选择使用两个部分、其中一个部分或者都不使用:

switch initializer; value {}

switch initializer {}

switch value {}

switch {}

很有趣,是吧?

使用字面布尔值的switch

有时候,可能会使用一个变量的switch语句,但这里有一种不同的方法。

考虑使用一个带有字面布尔值的switch语句。这种方法可以让我们检查多个条件,而不仅仅局限于一个变量的值。

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可能似乎是多余和无意义的。

它感觉有点像在陈述显而易见的事实,但好消息是Go有一种更简化的处理方式,可以像这样简化它:

switch { // <--- just remove `true`
    case a == 1 && b == 2:
    ...
}

这种简化的方法同样有效。

另外,switch语句也可以与false字面值一起使用,提供了一种确定哪些条件未满足的方法。

Switch短赋值

我们经常忽视switch语句中的初始化器部分。

但它非常有用,与if语句或for循环中的初始化器类似。它允许你声明并赋值一个变量,然后立即使用它。

下面是一个例子来说明这一点:

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的两个部分吗?

你也可以选择只使用初始化器部分,当你这样做时,值部分被假定为true:

switch a := 1 {
    case a == 1:
    fmt.Println("a is 1")
    case a == 2:
    fmt.Println("a is 2")
}

到目前为止,我们已经看到了四种组织switch语句的方式:只使用初始化器、只使用值、两者都使用或者两者都不使用。但我们的重点主要在于switch本身。

接下来,我们将深入探讨case部分的作用以及如何在代码中充分利用它。

包含多个值的case

你可以在一个case中组合多个值。这种方法可以使你的代码更简洁易读:

switch a := 1; a {
    case 1, 2, 3: // <--
    fmt.Println("a is 1, 2 or 3")
}

很多Go的新手并不知道这个功能。相反,他们可能会写出这样的代码:

switch a := 1; a {
    case 1:
case 2:
case 3:
    fmt.Println("a is 1, 2 or 3")
}

但这种方法并不完全正确,因为switch在Go中的工作方式不同。

在这个例子中,打印语句只与最后一个case(case 3)相关联。所以,如果a是1或2,什么也不会发生,因为这些case后面没有指令,程序会直接跳过它们。

使用fallthrough关键字的case

这个关键字允许执行继续到下一个case而不检查其条件。这与大多数语言处理switch case的方式有些不同。

下面是一个例子来展示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")
}

输出会是什么?

在这种情况下,当a为1时,程序首先打印“a is 1”。然后,由于fallthrough关键字的存在,它会立即跳转到下一个case(case 2),而不检查a是否实际上为2。所以,它也会打印出“Now in case 2”。

你仍然可以在case 2中使用fallthrough关键字,程序会继续执行下一个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关键字绕过了下一个case的条件检查。因此,在switch语句的最后一个case中不使用它,因为没有后续的case可以过渡到。

默认情况和其细微差别

Go中的switch语句的默认情况类似于if语句中的else部分。

当没有任何其他case匹配时,它将执行默认情况,但是在Go中,默认情况有一些有趣的特点:

尽管在大多数编程语言中,默认情况通常放在末尾,但在Go中,它可以放置在switch语句的任何位置。大多数人为了清晰起见会把它放在末尾,但让我们看看当我们把它放在开头时会发生什么:

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")
}

在这个例子中,即使默认情况首先出现,它仍然被视为最后的选择,只有在没有其他case匹配时才会执行。

但还有另一层可以探索。

如果我们将默认情况与fallthrough关键字混合使用会怎么样?让我们来看看:

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

在这种情况下,当a为3时,switch从默认情况开始,打印“Neither 1 nor 2”。然后,由于fallthrough的存在,它会移动到下一个case,打印“a is 1”。

带有类型断言的switch

switch语句不仅可以处理值,还可以处理类型。这在处理接口时特别有用。

类型断言是实现这一功能的特性,它允许检查接口值的类型,并根据该类型运行不同的代码段:

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是一个存储字符串的接口变量。

switch语句使用i.(type)来确定i的类型,然后根据该类型选择要执行的case:

  • 它逐个检查每个case是否为特定类型(如int或string)。
  • 在每个case中,v表示i作为该case中检查的类型的值,因此可以像使用该类型的任何变量一样使用v。

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...