Условные выражения дают программистам возможность предписывать программам производить определенные действия, если условие выполняется, и другое действие, если условие не выполняется. Нам часто нужно сравнивать определенную переменную с разными возможными значениями и выполнять разные действия для разных результатов. Это можно реализовать, используя только операторы if
. Однако написание программного обеспечения предусматривает необходимость не только делать так, чтобы все работало, но и показывать свои намерения себе и другим разработчикам. switch
— это альтернативный условный оператор, с помощью которого удобно показывать действия программ Go в ситуациях с разными возможными вариантами.
Все, что можно написать с помощью оператора switch, можно написать и с помощью операторов if
. В этом обучающем руководстве мы рассмотрим несколько примеров того, что может делать оператор switch, как оно может заменить операторы if
, и в каких случаях его лучше применять.
Оператор switch обычно используются для описания действий, которые выполняет программа, когда переменная принимает определенные значения. В следующем примере показано, как добиться этого с помощью выражений if
:
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
if flav == "strawberry" {
fmt.Println(flav, "is my favorite!")
continue
}
if flav == "vanilla" {
fmt.Println(flav, "is great!")
continue
}
if flav == "chocolate" {
fmt.Println(flav, "is great!")
continue
}
fmt.Println("I've never tried", flav, "before")
}
}
Результат будет выглядеть следующим образом:
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
В main
мы определяем срез вкусов мороженого. Затем мы используем цикл for
для итерации. Мы используем три оператора if
для вывода разных сообщений, показывающих разные предпочитаемые вкусы мороженого. Каждый оператор if
должен использовать оператор continue
для остановки выполнения цикла for
, чтобы последнее сообщение по умолчанию не выводилось для предпочитаемых вкусов мороженого.
При добавлении новых вкусов мороженого нам нужно добавлять операторы if
для каждого нового случая. Для дублирующихся сообщений, как в случае с "vanilla"
и "chocolate"
, следует использовать дублирующиеся операторы if
. Тем, кто будет читать наш код в будущем (в том числе и нам), будет сложнее понять код из-за большого количества повторяющихся операторов if
, что затрудняет понимание их функции — сравнение переменной с разными значениями и выполнение разных действий. Кроме того, общее сообщение задается отдельно от условий и выглядит не связанным с ними. Оператор switch
поможет нам лучше организовать эту логику.
Оператор switch
начинается с ключевого слова switch
, за которым идет переменная в базовой форме, для которой производится сравнение. Далее идет пара фигурных скобок ({}
), в которых могут быть заключены разные варианты. Варианты описывают, какие действия должна выполнять программа Go, если переданная оператору switch переменная имеет значение, указанное в данном варианте. В следующем примере предыдущий пример конвертирован с использованием оператора switch
вместо нескольких операторов if
:
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
switch flav {
case "strawberry":
fmt.Println(flav, "is my favorite!")
case "vanilla", "chocolate":
fmt.Println(flav, "is great!")
default:
fmt.Println("I've never tried", flav, "before")
}
}
}
Результат выглядит так же:
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
I've never tried banana before
Мы снова определяем срез вкусов мороженого в программе main
и используем выражение range
для итерации вкусов. Однако в данном случае мы используем выражение switch
, которое оценивает переменную flav
. Мы используем два выбирающих
предложения для указания предпочтений. Нам больше не требуются операторы continue
, поскольку только один вариант
выполняется оператором switch
. Также мы сможем комбинировать дублирующуюся логику условий "chocolate"
и "vanilla"
, разделив их запятой в объявлении варианта
. Вариант default
используется как универсальный для всех случаев. Оно выполняется для всех вкусов, которые не включены в тело выражения switch
. В данном случае для варианта "banana"
будет использоваться программа default
и будет выведено сообщение I've never tried banana before
.
Упрощенная форма оператора switch
используется в самом распространенном случае: при сравнении переменной с несколькими альтернативными значениями. Также она обеспечивает дополнительное удобство, если мы хотим выполнять одно и то же действие для нескольких разных значений и другое действие, если не выполняется ни одно из заданных условий. Для этого используется ключевое слово default
.
Если упрощенная форма оператора switch
слишком узкая, мы можем использовать более общую форму оператора switch
.
Операторы switch
полезны для группировки наборов более сложных условных операторов, чтобы показать их связь. Это чаще всего применяется при сравнении переменной с диапазоном переменных, а не с определенными значениями, как было показано в предыдущем примере. В следующем примере игра на отгадывание реализована с помощью операторов if
, но ее можно улучшить с помощью оператора switch
:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
target := rand.Intn(100)
for {
var guess int
fmt.Print("Enter a guess: ")
_, err := fmt.Scanf("%d", &guess)
if err != nil {
fmt.Println("Invalid guess: err:", err)
continue
}
if guess > target {
fmt.Println("Too high!")
continue
}
if guess < target {
fmt.Println("Too low!")
continue
}
fmt.Println("You win!")
break
}
}
Результат зависит от случайного числа и от того, как хорошо вы играете в игру. Вот пример результатов одного игрового сеанса:
OutputEnter a guess: 10
Too low!
Enter a guess: 15
Too low!
Enter a guess: 18
Too high!
Enter a guess: 17
You win!
Для нашей игры на отгадывание требуется случайное число для сравнения, и поэтому мы используем функцию rand.Intn
из пакета math/rand
. Чтобы убедиться в получении разных значений target
при каждой игре мы используем rand.Seed
для рандомизации генератора случайных чисел по текущему времени. Аргумент 100
для rand.Intn
дает нам число в диапазоне 0–100. Затем мы используем цикл for
для сбора предположений игрока.
Функция fmt.Scanf
дает нам способ считывания вводимых пользователем данных в и сохранения в переменную по нашему выбору. Она использует глагол строки формата, конвертирующий вводимые пользователем данные в ожидаемый нами тип. Здесь %d
означает, что мы ожидаем значение int
, и мы передаем адрес переменной guess
, чтобы у fmt.Scanf
была возможность задать эту переменную. После обработки всех ошибок парсинга мы используем два оператора if
для сравнения догадки пользователя со значением target
. Возвращаемая строка
вместе с булевым значением
определяют, какое сообщение будет выведено игроку, и будет ли закрыта игра.
Эти операторы if
скрывают тот факт, что все значения в диапазоне, с которым сравнивается переменная, связаны друг с другом. При этом сложно сразу определить, не пропустили ли мы какую-то часть диапазона. В следующем примере предыдущий пример модифицирован с использованием оператора switch
:
package main
import (
"fmt"
"math/rand"
)
func main() {
target := rand.Intn(100)
for {
var guess int
fmt.Print("Enter a guess: ")
_, err := fmt.Scanf("%d", &guess)
if err != nil {
fmt.Println("Invalid guess: err:", err)
continue
}
switch {
case guess > target:
fmt.Println("Too high!")
case guess < target:
fmt.Println("Too low!")
default:
fmt.Println("You win!")
return
}
}
}
Результат выглядит примерно следующим образом:
OutputEnter a guess: 25
Too low!
Enter a guess: 28
Too high!
Enter a guess: 27
You win!
В этой версии игры на отгадывание мы заменили блок операторов if
на оператора switch
. Мы пропускаем аргумент выражения для switch
, поскольку мы используем switch
только для объединения условий. Каждое выбирающее
предложение содержит отдельное выражение сравнения guess
и target
. Как и в первом случае, когда мы заменили операторы if
на оператор switch
, нам больше не нужно использовать выражения continue
, поскольку выполняется только одно выбирающее предложение
. Наконец, выражение default
отвечает за случай, когда guess == target
, поскольку все остальные возможные варианты рассмотрены в двух других выбирающих предложениях
.
В приведенных примерах выполнялось только одно выбирающее выражение. Иногда нужно объединить варианты поведения нескольких выбирающих предложений
. Оператор switch
имеет еще одно ключевое слово для этой цели.
Иногда нам необходимо повторно использовать код, содержащийся в другом выбирающем
предложении. В таких случаях можно указать Go запустить тело следующего выбирающего
предложения, указанного с помощью ключевого слова fallthrough
. В следующем примере мы изменяем предыдущий пример со вкусами мороженого, чтобы более точно отразить нашу любовь к клубничному мороженому:
package main
import "fmt"
func main() {
flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
for _, flav := range flavors {
switch flav {
case "strawberry":
fmt.Println(flav, "is my favorite!")
fallthrough
case "vanilla", "chocolate":
fmt.Println(flav, "is great!")
default:
fmt.Println("I've never tried", flav, "before")
}
}
}
Результат будет выглядеть примерно так:
Outputchocolate is great!
vanilla is great!
strawberry is my favorite!
strawberry is great!
I've never tried banana before
Как мы уже видели, мы определяем срез строк
для представления вкусов и используем цикл for
для итерации. Здесь оператор switch
повторяет использованный ранее, но в нем используется ключевое слово fallthrough
в конце выбирающего предложения
для варианта "strawberry"
. Так Go запускает тело case "strawberry":
и вначале выводит строку strawberry is my favorite!
. При появлении fallthrough
выполняется тело следующего выбирающего предложения
. При этом будет выполнено тело выражения case "vanilla", "chocolate":
и будет выведен текст strawberry is great!
.
Ключевое слово fallthrough
нечасто используется разработчиками на Go. Обычно повторное использование кода, реализуемое через ключевое слово fallthrough
, лучше обеспечить посредством определения функции в общем коде. По этой причине использовать fallthrough
не рекомендуется.
Оператор switch
помогает нам передать другим разработчикам, читающим наш код, что сравниваемые значения в наборе как-то связаны друг с другом. Это упрощает добавление других вариантов поведения и позволяет правильно обрабатывать все варианты, которые мы могли забыть благодаря использованию default
. Когда вы в следующей раз будете писать код с несколькими оператора if
для одной и той же переменной, попробуйте переписать его с помощью switch
. Так вам будет проще переделать код, если в будущем потребуется добавить другие альтернативные значения.
Если вы хотите узнать больше о языке программирования Go, ознакомьтесь с нашей серией статей о программировании на языке Go.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!