blob: 50cf86bd8921c382c875fcefbd36578479edaf27 [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
Dave Day0d6986a2014-12-10 15:02:18 +1100106// Unpack 4 bytes into uint32 to repack into base 85 5-byte.
107var v uint32
108switch len(src) {
109default:
110 v |= uint32(src[3])
111 fallthrough
112case 3:
113 v |= uint32(src[2]) << 8
114 fallthrough
115case 2:
116 v |= uint32(src[1]) << 16
117 fallthrough
118case 1:
119 v |= uint32(src[0]) << 24
120}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100121```
122[src/pkg/encoding/ascii85/ascii85.go](http://golang.org/src/pkg/encoding/ascii85/ascii85.go#L43)
123
124The 'fallthrough' must be the last thing in the case; you can't write something like
125
emersion664cdd92016-06-14 15:42:32 +0200126```go
Dave Day0d6986a2014-12-10 15:02:18 +1100127switch {
128case f():
129 if g() {
130 fallthrough // Does not work!
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100131 }
Dave Day0d6986a2014-12-10 15:02:18 +1100132 h()
133default:
134 error()
135}
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100136```
alanfoeda917f2015-10-19 10:13:00 +0100137However, you can work around this by using a 'labeled' `fallthrough`:
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100138
emersion664cdd92016-06-14 15:42:32 +0200139```go
alanfoeda917f2015-10-19 10:13:00 +0100140switch {
141case f():
142 if g() {
143 goto nextCase // Works now!
144 }
145 h()
146 break
147nextCase:
148 fallthrough
149default:
150 error()
151}
152```
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100153## Multiple cases
154
155If you want to use multiple values in the same case, use a comma-separated list.
156
emersion664cdd92016-06-14 15:42:32 +0200157```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100158func letterOp(code int) bool {
159 switch chars[code].category {
160 case "Lu", "Ll", "Lt", "Lm", "Lo":
161 return true
162 }
163 return false
164}
165```
166## Type switch
167
168With a type switch you can switch on the type of an interface value (only):
169
emersion664cdd92016-06-14 15:42:32 +0200170```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100171func typeName(v interface{}) string {
172 switch v.(type) {
173 case int:
174 return "int"
175 case string:
176 return "string"
177 default:
178 return "unknown"
179 }
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100180}
181```
182
183You can also declare a variable and it will have the type of each ` case `:
184
emersion664cdd92016-06-14 15:42:32 +0200185```go
Andrew Gerrand5bc444d2014-12-10 11:35:11 +1100186func do(v interface{}) string {
187 switch u := v.(type) {
188 case int:
189 return strconv.Itoa(u*2) // u has type int
190 case string:
191 mid := len(u) / 2 // split - u has type string
192 return u[mid:] + u[:mid] // join
193 }
194 return "unknown"
195}
196
197do(21) == "42"
198do("bitrab") == "rabbit"
199do(3.142) == "unknown"
Ivan Vazquez77e5dbb2017-03-30 14:20:45 -0700200```
201
202## Noop case
203
204Sometimes 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.
205
206```go
207func pluralEnding(n int) string {
208 ending := ""
209
210 switch n {
211 case 1:
212 default:
213 ending = "s"
214 }
215
216 return ending
217}
218
219fmt.Sprintf("foo%s\n", pluralEnding(1)) == "foo"
220fmt.Sprintf("bar%s\n", pluralEnding(2)) == "bars"
221
222```
223