blob: 2609c9deb88fc9331f80eb9f6c4cef913cb85ac7 [file] [log] [blame] [view]
# Switch
Spec: http://golang.org/doc/go_spec.html#Switch_statements
Go's ` switch ` statements are pretty neat. For one thing, you don't need to break at the end of each case.
```
switch c {
case '&':
esc = "&"
case '\'':
esc = "'"
case '<':
esc = "&lt;"
case '>':
esc = "&gt;"
case '"':
esc = "&quot;"
default:
panic("unrecognized escape character")
}
```
[src/pkg/html/escape.go](http://golang.org/src/pkg/html/escape.go#L178)
## Not just integers
Switches work on values of any type.
```
switch syscall.OS {
case "windows":
sd = &sysDir{
Getenv("SystemRoot") + `\system32\drivers\etc`,
[]string{
"hosts",
"networks",
"protocol",
"services",
},
}
case "plan9":
sd = &sysDir{
"/lib/ndb",
[]string{
"common",
"local",
},
}
default:
sd = &sysDir{
"/etc",
[]string{
"group",
"hosts",
"passwd",
},
}
}
```
## Missing expression
In 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:
```
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
```
## Break
Go's ` switch ` statements ` break ` implicitly, but ` break ` is still useful:
```
command := ReadCommand()
argv := strings.Fields(command)
switch argv[0] {
case "echo":
fmt.Print(argv[1:]...)
case "cat":
if len(argv) <= 1 {
fmt.Println("Usage: cat <filename>")
break
}
PrintFile(argv[1])
default:
fmt.Println("Unknown command; try 'echo' or 'cat'")
}
```
## Fall through
To fall through to a subsequent case, use the ` fallthrough ` keyword:
```
// Unpack 4 bytes into uint32 to repack into base 85 5-byte.
var v uint32
switch len(src) {
default:
v |= uint32(src[3])
fallthrough
case 3:
v |= uint32(src[2]) << 8
fallthrough
case 2:
v |= uint32(src[1]) << 16
fallthrough
case 1:
v |= uint32(src[0]) << 24
}
```
[src/pkg/encoding/ascii85/ascii85.go](http://golang.org/src/pkg/encoding/ascii85/ascii85.go#L43)
The 'fallthrough' must be the last thing in the case; you can't write something like
```
switch {
case f():
if g() {
fallthrough // Does not work!
}
h()
default:
error()
}
```
However, you can work around this by using a 'labeled' `fallthrough`:
```
switch {
case f():
if g() {
goto nextCase // Works now!
}
h()
break
nextCase:
fallthrough
default:
error()
}
```
## Multiple cases
If you want to use multiple values in the same case, use a comma-separated list.
```
func letterOp(code int) bool {
switch chars[code].category {
case "Lu", "Ll", "Lt", "Lm", "Lo":
return true
}
return false
}
```
## Type switch
With a type switch you can switch on the type of an interface value (only):
```
func typeName(v interface{}) string {
switch v.(type) {
case int:
return "int"
case string:
return "string"
default:
return "unknown"
}
}
```
You can also declare a variable and it will have the type of each ` case `:
```
func do(v interface{}) string {
switch u := v.(type) {
case int:
return strconv.Itoa(u*2) // u has type int
case string:
mid := len(u) / 2 // split - u has type string
return u[mid:] + u[:mid] // join
}
return "unknown"
}
do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"
```