Показаны сообщения с ярлыком switch утверждения (switch statements) в Go. Показать все сообщения
Показаны сообщения с ярлыком switch утверждения (switch statements) в Go. Показать все сообщения

среда, 26 февраля 2020 г.

Пять паттернов использования операторов switch

Базовый switch с default кейсом

  • Оператор switch запускает первый case (кейс), равный выражению условия.
  • Кейсы оцениваются сверху вниз, останавливаясь, когда кейс подходит.
  • Если ни один кейс не совпадает и есть default кейс, выполняются его утверждения.

switch time.Now().Weekday() {
case time.Saturday:
    fmt.Println("Сегодня суббота.")
case time.Sunday:
    fmt.Println("Сегодня воскресенье.")
default:
    fmt.Println("Сегодня будничный день.")
}

В отличие от C и Java, выражения case не обязательно должны быть константами.

Без выражения условия

Switch без условия аналогичен switch true.

// пропущенное выражение условия означает "true"
switch hour := time.Now().Hour(); { 
case hour < 12:
    fmt.Println("Доброе утро!")
case hour < 17:
    fmt.Println("Добрый день!")
default:
    fmt.Println("Добрый вечер!")
}

Кейс - список

В Go в качестве кейса можно использовать список значений - если выражение условия совпадает с одним из элементов списка, тогда кейс считается совпавшим:

func WhiteSpace(c rune) bool {
    switch c {
    case ' ', '\t', '\n', '\f', '\r':
        return true
    }
    return false
}

Fallthrough (проваливание в следующий кейс)

Оператор fallthrough передает управление следующему кейсу.

Он может использоваться только как заключительное утверждение в выражениях кейса.

switch 2 {
case 1:
    fmt.Println("1")
    fallthrough
case 2:
    fmt.Println("2")
    fallthrough
case 3:
    fmt.Println("3")
}

Вывод:

2
3

Выход с break

Оператор break завершает выполнение самого внутреннего оператора for, switch или select.

Если вам нужно выйти из окружающего цикла, а не из switch, вы можете поместить метку в цикл и перейти к этой метке. Следующий пример показывает оба варианта использования.

Loop:
    for _, ch := range "a b\nc" {
        switch ch {
        case ' ': // пропускаем пробел
            break
        case '\n': // break на newline символе
            break Loop
        default:
            fmt.Printf("%c\n", ch)
        }
    }

Вывод:

a
b

На символе a выполняется default кейс. На пробеле оператор break производит выход из switch. Далее на символе b выполняется default кейс. Далее на символе новой строки (newline - \n) происходит выход к метке Loop и выход из for range цикла.

Порядок исполнения

  • Сначала выражение switch оценивается один раз.
  • Затем case выражения оцениваются слева направо и сверху вниз:
    • первое, равное выражению switch, запускает выполнение операторов соответствующего case,
    • другие case пропущены.

// Foo печатает и возвращает n.
func Foo(n int) int {
    fmt.Println(n)
    return n
}

func main() {
    switch Foo(2) {
    case Foo(1), Foo(2), Foo(3):
        fmt.Println("Первый case")
        fallthrough
    case Foo(4):
        fmt.Println("Второй case")
    }
}

Вывод:

2
1
2
Первый case
Второй case


Читайте также:


вторник, 18 июня 2019 г.

Спецификация Go: switch утверждения (switch statements), переключатели выражений (expression switch)

Утверждения "switch" (переключатель) обеспечивают многовариантное исполнение. Спецификатор выражения или типа сравнивается с "cases" (случаи) внутри "switch", чтобы определить, какую ветвь выполнить.

SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .

Существует две формы: переключатели выражения (expression switch) и переключатели типа (type switch). В переключателе выражений случаи содержат выражения, которые сравниваются со значением выражения переключателя. В переключателе типов случаи содержат типы, которые сравниваются с типом специально аннотированного выражения переключателя. Выражение switch вычисляется ровно один раз в операторе switch.

Переключатели выражений (expression switch)

В переключателе выражений switch выражение оценивается, а case выражения, которые не обязательно должны быть константами, оцениваются слева направо и сверху вниз; первое, равное выражению переключателя, запускает выполнение утверждений соответствующего случая; другие case пропускаются. Если ни один case не соответствует и существует "default" case (случай по умолчанию), то выполняются его утверждения. Может быть не более одного случая по умолчанию, и он может появляться где угодно в "switch" утверждении. Отсутствующее выражение переключателя эквивалентно логическому значению true.

ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .

Если выражение switch оценивается как нетипизированная константа, оно сначала неявно преобразуется в тип по умолчанию; если это нетипизированное логическое значение, оно сначала неявно преобразуется в тип bool. Предварительно объявленное нетипизированное значение nil нельзя использовать в качестве выражения переключения.

Если выражение case не типизировано, оно сначала неявно преобразуется в тип выражения switch. Для каждого (возможно преобразованного) выражения case x и значения t выражения-переключателя x == t должно быть допустимым сравнением.

Другими словами, выражение switch обрабатывается так, как если бы оно использовалось для объявления и инициализации временной переменной t без явного типа; это та величина t, с которой каждое выражение x случая проверяется на равенство.

В case или default блоках последнее непустое утверждение может быть (возможно, помечено (labeled)) утверждением "провала" ("fallthrough" statement), чтобы указать, что управление должно перетекать из конца этого пункта в первое утверждение следующего пункта. В противном случае управление переходит к концу утверждения "switch". Утверждение "fallthrough" может появляться как последнее утверждение всего, кроме последнего пункта переключателя выражений.

Выражению-переключателю может предшествовать простое утверждение, которое выполняется до того, как выражение будет оценено.

switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}

// пропущенное выражение переключателя означает "true"
switch x := f(); {  
case x < 0: return -x
default: return x
}

switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}

Ограничение реализации: компилятор может запретить множественные выражения с одинаковыми константами. Например, текущие компиляторы запрещают дублирующиеся целочисленные, с плавающей точкой или строковые константы в case выражениях.


Читайте также: