Skip to content
Andrew Gerrand edited this page Dec 10, 2014 · 11 revisions

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

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

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()
	}

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"
	}
	panic("unreachable")
}

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"
Clone this wiki locally