首先以一个小问题开头。请问下面这个程序的编译运行将表现出何种行为?三个选项:
package main
func alwaysFalse() bool {
return false
}
func main() {
switch alwaysFalse()
{
case true:
println("真")
case false:
println("假")
}
}
(先思考一下,答案需翻页。)
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
OK,公布答案。答案是 2,打印输出“真”。答对的可随意继续或返回。答错的同志继续阅读下面的解释。
有些答错的同志可能觉得此程序编译不过,因为switch
代码块的开大括号{
被放在了下一行,这在 Go 中时不允许的。其实非也,其实 Go 语言的断行规则定义如下:
break
、continue
、fallthrough
和return
;++
或者自减运算符--
;)
、]
或}
。很多人印象中的规则“代码块的开大括号不能被放在下一行”其实只是一个通常的而非普适的规则。根据上述规则,上面这个程序中的 switch 代码块在编译前将被改写为如下所示(注意插入的几个分号):
switch alwaysFalse();
{
case true:
println("真");
case false:
println("假");
};
另外有些答错的同志可能觉得此程序运行时应该打印输出“假”。这里,我们还需要知道 Go 中关于switch
代码块的另一个常识:switch
代码块中开大括号{前的比较表达式可以省略,其默认值为true
。因此上面这个switch
代码块将被继续改写为如下所示:
switch alwaysFalse();
true {
case true:
println("真");
case false:
println("假");
};
到此为止,我们可以清楚地得知此程序为什么会打印输出“真”了。
结尾展示另外一段编译没问题但有些不符常规的代码:
package main
func main() {
for i, j := 0, 10
i < 10
j-- {
if i++
i > j {
break
}
println(i)
}
}
本文首发在微信 Go 101 公众号,欢迎各位转载本文。Go 101 公众号将尽量在每个工作日发表一篇原创短文,有意关注者请扫描下面的二维码。
1
gamexg 2019-05-08 21:59:38 +08:00
项目中这么写会被打死吧?
ide 自动格式化代码,变成了: ``` package main func alwaysFalse() bool { return false } func main() { switch alwaysFalse(); { case true: println("真") case false: println("假") } } ``` |
2
acehow 2019-05-08 22:16:21 +08:00 via Android
这种莫名其妙的写法有什么意义哦。能写出这种代码只能说明这人根本不会 go 语言。
|
4
zhujinliang 2019-05-08 22:26:57 +08:00 via iPhone
感谢分享,以后碰到类似 bug 可以注意到这个问题
|
5
AngelCriss 2019-05-08 22:34:48 +08:00 via Android 9
这不就是说 go 语言设计傻逼吗
|
6
SuperMild 2019-05-08 22:44:02 +08:00
在这个 IDE/编辑器智能提醒已经是标配的年代,这些知识已经意义不大了。
|
7
whoami9894 2019-05-08 23:03:54 +08:00 via Android
> switch 代码块中开大括号{前的比较表达式可以省略,其默认值为 true
这句话的含义是? ``` switch { case true: xx case false: xx } switch a{ case 1: xx case 2: xx } ``` 只有第一种类似 cond 的语义可以忽略吧 |
8
liulaomo OP @whoami9894
>> switch 代码块中开大括号{前的比较表达式可以省略,其默认值为 true > 这句话的含义是? 其实 switch 代码块中开大括号{前的简单语句也可以省略,因此有以下 4 种变种: ``` switch aSimpleStatement; anExpression {...} switch aSimpleStatement; {...} // <=> switch aSimpleStatement; true {...} switch anExpression {...} switch {...} .. <=> switch true {...} ``` |
9
whoami9894 2019-05-09 00:09:39 +08:00 via Android
@liulaomo
噢噢理解错了,现在明白你的意思了,是因为 go 分支语句的糖导致的。alwaysFalse()被当做 statement 了 |
10
gramyang 2019-05-09 07:58:27 +08:00 1
go 语言的大括号是不能像 c++那样换行写的。因为 go 默认给每行语句添加一个;,这篇文章能解决所有问题 https://segmentfault.com/a/1190000013739000
|
11
usingnamespace 2019-05-09 09:20:23 +08:00 via iPhone
@SuperMild 确实 别整些这种没用的玩意
|
12
usingnamespace 2019-05-09 09:20:53 +08:00 via iPhone
@zhujinliang ?这样写 go 的代码不怕被骂死?
|
13
liulaomo OP @gramyang
> go 语言的大括号是不能像 c++那样换行写的。因为 go 默认给每行语句添加一个; 我感觉这篇文章白写了, ;D 本文重在阐述断行规则,;) => 很多人印象中的规则“代码块的开大括号不能被放在下一行”其实只是一个通常的而非普适的规则。 |
14
Muninn 2019-05-09 09:57:48 +08:00
我觉得楼主分享的挺好的,怎么这么多人喷。
|
15
reus 2019-05-09 10:08:29 +08:00
写了几年 go,没想到 switch 还能定义变量…… 虽然 switch v := v.(type) 也没少写……
|
16
HarrisonZ 2019-05-09 10:19:26 +08:00
茴香豆有几种写法~~~
|
17
lyy16384 2019-05-09 10:30:08 +08:00
不会 go,谁解释一下 true{case}这样的语句为什么能被当成 switch ?难道和上一行加了分号的 switch 还是同一条语句吗
还有这种自动写一个 true 在中间的设计有什么好处 |
18
zhujinliang 2019-05-09 10:48:08 +08:00 via iPhone
@usingnamespace
昨晚没看仔细 正常这个问题不应该发生,一般使用 if 判断布尔分支,不应出现使用 switch 对 bool 型进行分支的做法。 使用包装过的 bool 型是否会出现问题?测试了 type Boolean bool,之后使用 Boolean 类型,编译不通过,提示 mismatched types Boolean and bool,意味着假设使用 bool 做了个只有两种情况的枚举(不建议这样做),之后 case 每种情况,也不会出现问题。但注意 type Boolean = bool 形式可以编译通过。 如果编译报错,出现在 switch 附近,提示什么类型不匹配,可以先注意下是否多打了换行,避免傻呵呵地找类型问题🌝 |
19
lepig 2019-05-09 11:00:59 +08:00
作为新手来学习一下
|
20
AngryPanda 2019-05-09 11:05:54 +08:00
这种代码根本没办法通过 lint 检查
|
21
TypeErrorNone 2019-05-09 11:26:59 +08:00
go fmt 格式化一下
这么写不就是之前学 c 的时候如何计算 ++i++ 嘛 |
22
rvtea 2019-05-09 16:43:25 +08:00
这么写确实容易被打死啊。。。
去 playground 贴上代码然后 format 一下之后就看出端倪了,反正确实不太可能这么写吧,真这么写的估计踩着坑之后会😤 |
23
luw2007 2019-05-20 09:59:12 +08:00
package main
func alwaysFalse() bool { return false } func main() { switch alwaysFalse();{ case true: println("真") case false: println("假") } } 多了个分号,然后语义变了。 这块确实要注意。 |
24
luw2007 2019-05-20 09:59:51 +08:00
```golang
package main func alwaysFalse() bool { return false } func main() { switch alwaysFalse();{ case true: println("真") case false: println("假") } } ``` 多了个分号,然后语义变了。 这块确实要注意。 |