blob: 2609c9deb88fc9331f80eb9f6c4cef913cb85ac7 [file] [log] [blame] [view]
Andrew Gerrand5bc444d2014-12-10 11:35:11 +11001# Switch
2
3Spec: http://golang.org/doc/go_spec.html#Switch_statements
4
5Go's ` switch ` statements are pretty neat. For one thing, you don't need to break at the end of each case.
6
7```
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
30```
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
66```
67func 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
84```
85command := 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
105```
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
126```
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
alanfoeda917f2015-10-19 10:13:00 +0100139```
140switch {
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
157```
158func 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
170```
171func 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
185```
186func 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"
200```