| # 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 = "<" |
| case '>': |
| esc = ">" |
| case '"': |
| esc = """ |
| 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" |
| ``` |