blob: 5bbebc53a990343eaa38c69103942b771629d05e [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001# Switch
2
Baiju Muthukadan0384a102016-03-20 08:46:31 +05303Spec: https://golang.org/ref/spec#Switch_statements
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11004
5Go's ` switch ` statements are pretty neat. For one thing, you don't need to break at the end of each case.
6
emersion664cdd92016-06-14 15:42:32 +02007```go
Dave Day0d6986a2014-12-10 15:02:18 +11008switch c {
9case '&':
10 esc = "&"
11case '\'':
12 esc = "'"
13case '<':
14 esc = "&lt;"
15case '>':
16 esc = "&gt;"
17case '"':
18 esc = "&quot;"
19default:
20 panic("unrecognized escape character")
21}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110022```
23
24[src/pkg/html/escape.go](http://golang.org/src/pkg/html/escape.go#L178)
25
26## Not just integers
27
28Switches work on values of any type.
29
emersion664cdd92016-06-14 15:42:32 +020030```go
Dave Day0d6986a2014-12-10 15:02:18 +110031switch syscall.OS {
32case "windows":
33 sd = &sysDir{
34 Getenv("SystemRoot") + `\system32\drivers\etc`,
35 []string{
36 "hosts",
37 "networks",
38 "protocol",
39 "services",
40 },
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110041 }
Dave Day0d6986a2014-12-10 15:02:18 +110042case "plan9":
43 sd = &sysDir{
44 "/lib/ndb",
45 []string{
46 "common",
47 "local",
48 },
49 }
50default:
51 sd = &sysDir{
52 "/etc",
53 []string{
54 "group",
55 "hosts",
56 "passwd",
57 },
58 }
59}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110060```
61
62## Missing expression
63
64In fact, you don't need to switch on anything at all. A switch with no value means "switch true", making it a cleaner version of an if-else chain, as in this example from Effective Go:
65
emersion664cdd92016-06-14 15:42:32 +020066```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110067func unhex(c byte) byte {
Dave Day0d6986a2014-12-10 15:02:18 +110068 switch {
69 case '0' <= c && c <= '9':
70 return c - '0'
71 case 'a' <= c && c <= 'f':
72 return c - 'a' + 10
73 case 'A' <= c && c <= 'F':
74 return c - 'A' + 10
75 }
76 return 0
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110077}
78```
79
80## Break
81
82Go's ` switch ` statements ` break ` implicitly, but ` break ` is still useful:
83
emersion664cdd92016-06-14 15:42:32 +020084```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110085command := ReadCommand()
86argv := strings.Fields(command)
87switch argv[0] {
88case "echo":
Dave Day0d6986a2014-12-10 15:02:18 +110089 fmt.Print(argv[1:]...)
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110090case "cat":
Dave Day0d6986a2014-12-10 15:02:18 +110091 if len(argv) <= 1 {
92 fmt.Println("Usage: cat <filename>")
93 break
94 }
95 PrintFile(argv[1])
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110096default:
Dave Day0d6986a2014-12-10 15:02:18 +110097 fmt.Println("Unknown command; try 'echo' or 'cat'")
Andrew Gerrand5bc444d2014-12-10 11:35:11 +110098}
99```
100
101## Fall through
102
103To fall through to a subsequent case, use the ` fallthrough ` keyword:
104
emersion664cdd92016-06-14 15:42:32 +0200105```go
Atila Romero63e14fa2018-08-02 16:21:07 -0300106v := 42
107switch v {
108case 100:
109 fmt.Println(100)
110 fallthrough
111case 42:
112 fmt.Println(42)
113 fallthrough
114case 1:
115 fmt.Println(1)
116 fallthrough
117default:
118 fmt.Println("default")
119}
120// Output:
121// 42
122// 1
123// default
124```
125
126Another example:
127
128```go
Dave Day0d6986a2014-12-10 15:02:18 +1100129// Unpack 4 bytes into uint32 to repack into base 85 5-byte.
130var v uint32
131switch len(src) {
132default:
133 v |= uint32(src[3])
134 fallthrough
135case 3:
136 v |= uint32(src[2]) << 8
137 fallthrough
138case 2:
139 v |= uint32(src[1]) << 16
140 fallthrough
141case 1:
142 v |= uint32(src[0]) << 24
143}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100144```
145[src/pkg/encoding/ascii85/ascii85.go](http://golang.org/src/pkg/encoding/ascii85/ascii85.go#L43)
146
147The 'fallthrough' must be the last thing in the case; you can't write something like
148
emersion664cdd92016-06-14 15:42:32 +0200149```go
Dave Day0d6986a2014-12-10 15:02:18 +1100150switch {
151case f():
152 if g() {
153 fallthrough // Does not work!
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100154 }
Dave Day0d6986a2014-12-10 15:02:18 +1100155 h()
156default:
157 error()
158}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100159```
alanfoeda917f2015-10-19 10:13:00 +0100160However, you can work around this by using a 'labeled' `fallthrough`:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100161
emersion664cdd92016-06-14 15:42:32 +0200162```go
alanfoeda917f2015-10-19 10:13:00 +0100163switch {
164case f():
165 if g() {
166 goto nextCase // Works now!
167 }
168 h()
169 break
170nextCase:
171 fallthrough
172default:
173 error()
174}
175```
alexcom4e9ead62018-09-25 18:12:41 +0300176Note: `fallthrough` does not work in type switch.
177
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100178## Multiple cases
179
180If you want to use multiple values in the same case, use a comma-separated list.
181
emersion664cdd92016-06-14 15:42:32 +0200182```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100183func letterOp(code int) bool {
184 switch chars[code].category {
185 case "Lu", "Ll", "Lt", "Lm", "Lo":
186 return true
187 }
188 return false
189}
190```
191## Type switch
192
193With a type switch you can switch on the type of an interface value (only):
194
emersion664cdd92016-06-14 15:42:32 +0200195```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100196func typeName(v interface{}) string {
197 switch v.(type) {
198 case int:
199 return "int"
200 case string:
201 return "string"
202 default:
203 return "unknown"
204 }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100205}
206```
207
208You can also declare a variable and it will have the type of each ` case `:
209
emersion664cdd92016-06-14 15:42:32 +0200210```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100211func do(v interface{}) string {
212 switch u := v.(type) {
213 case int:
214 return strconv.Itoa(u*2) // u has type int
215 case string:
216 mid := len(u) / 2 // split - u has type string
217 return u[mid:] + u[:mid] // join
218 }
219 return "unknown"
220}
221
222do(21) == "42"
223do("bitrab") == "rabbit"
224do(3.142) == "unknown"
Ivan Vazquez77e5dbb2017-03-30 14:20:45 -0700225```
226
227## Noop case
228
229Sometimes it useful to have cases that require no action. This can look confusing, because it can appear that both the noop case and the subsequent case have the same action, but isn't so.
230
231```go
232func pluralEnding(n int) string {
233 ending := ""
234
235 switch n {
236 case 1:
237 default:
238 ending = "s"
239 }
240
241 return ending
242}
243
244fmt.Sprintf("foo%s\n", pluralEnding(1)) == "foo"
245fmt.Sprintf("bar%s\n", pluralEnding(2)) == "bars"
246
247```
248