One place for hosting & domains

      Switch

      Como escrever instruções switch em Go


      Introdução

      As instruções condicionais dão aos programadores capacidade para direcionar seus programas a tomarem algumas medidas se uma condição for verdadeira e outra ação se a condição for falsa. Frequentemente, queremos comparar algumas variáveis com vários valores possíveis, tomando diferentes ações em cada circunstância. É possível fazer isso funcionar usando somente as instruções if. No entanto, escrever um software não diz respeito somente a fazer as coisas funcionarem, mas também de comunicar sua intenção para outros desenvolvedores e para si mesmo no futuro. O switch é uma instrução condicional alternativa útil para comunicar as ações tomadas pelos seus programas em Go quando diante de diferentes opções.

      Tudo o que podemos escrever com a instrução switch também pode ser escrito com as instruções if. Neste tutorial, vamos examinar alguns exemplos do que a instrução switch pode fazer, quais instruções if ela substitui e onde ela é mais adequadamente aplicada.

      Estrutura das instruções switch

      A instrução switch é geralmente usada para descrever as ações tomadas por um programa quando atribuímos valores específicos para uma variável. O exemplo a seguir demonstra como realizaríamos isso usando instruções 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")
          }
      }
      

      Isso gerará o seguinte resultado:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      Dentro de main, definimos uma fatia com sabores de sorvete. Na sequência, usamos um for loop para iterar por eles. Usamos três instruções if para imprimir diferentes mensagens que indicam preferências por diferentes sabores de sorvete. Cada instrução if deve usar a instrução continue para parar a execução do loop for, de modo que a mensagem padrão no final não seja impressa em relação aos sabores preferidos de sorvete.

      À medida que adicionamos novas preferências de sorvete, temos que continuar adicionando instruções if para lidar com os novos casos. As mensagens duplicadas, como no caso de "vanilla" e "chocolate", devem ter instruções if duplicadas. Para futuros leitores do nosso código (nós mesmos, inclusive), a natureza repetitiva das instruções if atrapalha o entendimento sobre parte importante do que elas estão fazendo — comparando a variável com vários valores e tomando diferentes ações. Além disso, nossa mensagem de fallback fica separada das condicionais, fazendo-a parecer não relacionada. A instrução switch pode nos ajudar a organizar essa lógica melhor.

      A instrução switch começa com a palavra-chave switch e é seguida, em sua forma mais básica, de algumas variáveis com as quais serão feitas comparações. Após a instrução vem um par de chaves ({}) onde várias cláusulas de caso podem aparecer. As cláusulas de caso descrevem as medidas que o seu programa em Go deve adotar quando a variável informada à instrução switch for igual ao valor referenciado pela cláusula de caso. O exemplo a seguir converte o exemplo anterior para que use uma switch em vez de várias instruções 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")
              }
          }
      }
      

      O resultado é o mesmo de antes:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      Mais uma vez, definimos uma fatia com sabores de sorvete em main e usamos a instrução range para iterar sobre cada sabor. Dessa vez, no entanto, usamos uma instrução switch que irá examinar a variável flav. Usamos duas cláusulas case para indicar as preferências. Já não precisamos de instruções continue, já que apenas uma cláusula case será executada pela instrução switch. Também podemos combinar a lógica duplicada das condicionais "chocolate" e "vanilla", separando cada uma com uma vírgula na declaração da cláusula case. A cláusula default serve como nossa cláusula catch-all [global]. Ela executará em relação a todos os sabores que ainda não foram contabilizados no corpo da instrução switch. Nesse caso, "banana" fará com que default seja executada, imprimindo a mensagem I've never tried banana before (Nunca experimentei o de banana antes).

      Essa forma simplificada de instruções switch lida com o uso mais comum dado a elas: comparar uma variável com várias alternativas. Ela também nos traz conveniência nos locais em que queremos tomar a mesma medida em relação a diversos valores diferentes e algumas outras medidas quando nenhuma das condições listadas forem atendidas pelo uso da palavra-chave default informada.

      Quando essa forma simplificada da switch mostra-se limitada, podemos usar uma forma mais geral da instrução switch.

      Instruções switch gerais

      As instruções switch são úteis para agrupar coleções de condicionais mais complicadas, mostrando que elas estão de alguma maneira relacionadas. Isso é mais comumente usado ao comparar algumas variáveis com uma gama de valores, em vez de valores específicos, como no exemplo anterior. O exemplo a seguir implementa um jogo de adivinhação usando instruções if que poderia ser beneficiado por uma instrução 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
          }
      }
      

      O resultado variará dependendo do número aleatório selecionado e do quão bem você jogar o jogo. Aqui está o resultado de uma sessão para exemplificar:

      Output

      Enter a guess: 10 Too low! Enter a guess: 15 Too low! Enter a guess: 18 Too high! Enter a guess: 17 You win!

      Nosso jogo de adivinhação precisa de um número aleatório contra o qual fazer as comparações. Portanto, usamos a função rand.Intn do pacote math/rand. Para garantir que obteremos diferentes valores para target toda vez que jogarmos o jogo, usamos o rand.Seed para aplicar um fator de aleatoriedade ao gerador de números aleatórios, com base no momento atual. O argumento 100 para rand.Intn nos dará um número no intervalo de 0-100. Então, usamos um loop for para começar a coletar adivinhações do jogador.

      A função fmt.Scanf nos oferece um meio para ler a entrada do usuário em uma variável de nossa escolha. Ela usa um verbo para a string de formato, a qual converte a entrada do usuário para o tipo que esperamos. O %d aqui significa que esperamos um int e enviamos o endereço da variável guess para que o fmt.Scanf consiga definir tal variável. Após lidar com quaisquer erros de análise, usamos duas instruções if para comparar a adivinhação do usuário com o valor target. A string que elas retornam, junto com o bool [booleano], controla a mensagem exibida para o jogador e também se o jogo fechará.

      Essas instruções if tornam vago o fato de que o intervalo de valores com o qual a variável está sendo comparada são todos relacionados de alguma maneira. À primeira vista, pode ser difícil dizer se perdemos alguma parte do intervalo. O exemplo a seguir refatora o exemplo anterior para usar uma instrução switch como alternativa:

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

      Isso gerará um resultado similar ao seguinte:

      Output

      Enter a guess: 25 Too low! Enter a guess: 28 Too high! Enter a guess: 27 You win!

      Nessa versão do jogo de adivinhação, substituímos o bloco de instruções if por uma instrução switch. Omitimos o argumento da expressão para switch porque somente estamos interessados em usar a instrução switch para coletar condicionais juntas. Cada cláusula case contém uma expressão diferente que compara o guess com o target. De maneira similar à primeira vez que substituímos instruções if pela switch, já não precisamos mais de instruções continue, já que apenas uma cláusula case será executada. Por fim, a cláusula default lida com o caso onde o guess == target, uma vez que cobrimos todos os outros valores possíveis com outras duas cláusulas case.

      Nos exemplos que vimos até agora, será executada exatamente uma instrução case. De vez em quando, você pode desejar combinar os comportamentos das várias cláusulas case. As instruções switch fornecem outra palavra-chave para alcançar este comportamento.

      Fallthrough

      As vezes será necessário reutilizar o código que outra cláusula case contém. Nesses casos, é possível pedir ao Go que execute o corpo da próxima cláusula case listada usando a palavra-chave fallthrough. Este próximo exemplo modifica nosso exemplo anterior de sabor de sorvete para refletir com maior precisão nosso entusiasmo por sorvete de morango:

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

      Vamos ver este resultado:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! strawberry is great! I've never tried banana before

      Como vimos anteriormente, definimos uma fatia da string para representar sabores e iterar ao longo dela usando um loop for. A instrução switch aqui é idêntica à que já vimos antes, porém com a adição da palavra-chave fallthrough ao final da cláusula case para "strawberry". Isso faz com que o Go execute o corpo de case "strawberry":, primeiro imprimindo a string strawberry is my favorite! (morango é o meu predileto!). Quando encontrar a palavra-chave fallthrough, executará o corpo da próxima cláusula case. Isso faz com que o corpo do case "vanilla", "chocolate" execute, imprimindo strawberry is great! (morango é uma ótimo!).

      A palavra-chave fallthrough não é usada frequentemente pelos desenvolvedores de Go. Normalmente, a reutilização de código realizada usando a palavra-chave fallthrough pode ser obtida de maneira melhor definindo-se uma função com o código comum. Por essas razões, o uso da palavra-chave fallthrough, no geral, é desencorajado.

      Conclusão

      As instruções switch nos ajudam a transmitir para outros desenvolvedores que leem nosso código que em um conjunto de comparações, elas estão de alguma maneira relacionadas. Elas facilitarão muito mais quando tivermos que adicionar comportamentos diferentes se um novo caso for adicionado no futuro e possibilitarão a garantia de que tudo o que esquecermos será devidamente tratato apropriadamente com as cláusulas default. A próxima vez que você se encontrar escrevendo várias instruções if, sendo que todas envolvem a mesma variável, tente reescrevê-las com uma instrução switch — será mais fácil revisar o trabalho quando for hora de considerar algum outro valor alternativo.

      Se quiser aprender mais sobre a linguagem de programação Go, confira toda a série sobre Como codificar na série Go.



      Source link

      Cómo escribir instrucciones switch en Go


      Introducción

      Las instrucciones condicionales brindan a los programadores la capacidad indicar a sus programas que realicen una acción si una condición es verdadera y otra si la condición es falsa. Con frecuencia, nos conviene comparar alguna variable con múltiples valores posibles y realizar diferentes acciones en cada circunstancia. Es posible lograr esto utilizando solo instrucciones if. Sin embargo, escribir software no solo se trata de lograr que las cosas funcionen, sino también de comunicar su intención a usted mismo en el futuro y a otros desarrolladores. switch es una instrucción condicional alternativa útil para comunicar las acciones realizadas por sus programas de Go cuando se les presentan diferentes opciones.

      Todo lo que podamos escribir con la instrucción de switch también se puede escribir con instrucciones if. En este tutorial, veremos algunos ejemplos de lo que puede lograr la instrucción switch, las instrucciones if que sustituye y en que situaciones se aplica de forma más adecuada.

      Estructura de las instrucciones Switch

      Switch se utiliza comúnmente para describir las acciones efectuadas por un programa cuando a una variable se le asignan valores específicos. En el siguiente ejemplo se muestra la forma en que lograríamos esto usando instrucciones 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")
          }
      }
      

      Esto generará el siguiente resultado:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      Dentro de main, definimos un slice de sabores de helado. Luego usaremos un for loop para iterarlos. Utilizamos tres instrucciones if para imprimir diferentes mensajes que indican preferencias por diferentes sabores de helado. Cada instrucción if debe usar la instrucción continue para detener la ejecución del bucle for, de modo que el mensaje predeterminado al final no se imprima para los sabores de helado preferidos.

      Al añadir nuevas preferencias de helado, debemos seguir agregando instrucciones if para manejar los nuevos casos. En los mensajes duplicados, como en el caso de “vanilla” y “chocolate”, deben estar duplicadas las instrucciones if. Para los futuros lectores de nuestro código (incluidos nosotros), la naturaleza repetitiva de las instrucciones if oculta la parte importante de lo que hacen, (cuando se compara la variable con varios valores y tomando y se toman diferentes acciones). Además, nuestro mensaje de reserva se distingue de los condicionales y hace que parezca que no está relacionado. La instrucción switch puede servirnos para organizar mejor esta lógica.

      La instrucción switch comienza con la palabra clave switch y le sigue, en su forma más básica, alguna variable contra la cual puedan realizarse comparaciones. A esto le sigue un par llaves ({}) en el que pueden aparecer varias_ cláusulas de caso_. Las cláusulas de caso describen las acciones que su programa de Go debe realizar cuando la variable proporcionada a la instrucción switch es igual al valor referido por las cláusulas de caso. El siguiente ejemplo convierte el ejemplo anterior para que utilice switch en lugar de varias instrucciones 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")
              }
          }
      }
      

      El resultado es el mismo que el anterior:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      Una vez más, definimos un segmento de sabores de helado en main y usamos la instrucción range para iterar cada sabor. Sin embargo, esta vez usamos una instrucción switch que examinará la variable flav. Utilizamos dos cláusulas case para indicar las preferencias. Ya no necesitamos las instrucciones continue porque la instrucción switch solo ejecutará una cláusula case. También podemos combinar la lógica duplicada de los condicionales “chocolate” y “vanilla” separando cada uno con una coma en la declaración de la cláusula case. La cláusula default sirve como cláusula general. Se ejecutará para cualquier sabor que no hayamos tenido en cuenta en el cuerpo de la instrucción switch. En este caso, “banana” hará que se ejecute default, con lo cual se imprimirá el mensaje I've never tried banana before.

      Esta forma simplificada de las instrucciones switch aborda el uso más común para ellas: comparar una variable con varias alternativas. También nos proporciona practicidad cuando queremos realizar la misma acción para varios valores diferentes y cualquier otra acción cuando no se cumple ninguna de las condiciones enumeradas al usar la palabra clave default.

      Cuando esta forma simplificada de switch resulta demasiado limitada, podemos usar una forma más general de la instrucción switch.

      Instrucciones generales de switch

      Las instrucciones switch son útiles para agrupar las colecciones de condicionales más complicadas a fin de mostrar que están de algún modo relacionadas. Esto se utiliza con mayor frecuencia al comparar una variable con un rango de valores, en lugar de valores específicos como en el ejemplo anterior. El siguiente ejemplo implementa un juego de adivinanzas usando instrucciones if que se podrían beneficiar con una instrucción 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
          }
      }
      

      El resultado puede variar dependiendo del número aleatorio que seleccionó y de lo bien que se desempeñe en el juego. A continuación, se muestra el resultado de una sesión de ejemplo:

      Output

      Enter a guess: 10 Too low! Enter a guess: 15 Too low! Enter a guess: 18 Too high! Enter a guess: 17 You win!

      En nuestro juego de adivinanzas se requiere un número al azar para compararlas, por lo que usamos la función rand.Intn del paquete math/rand. A fin de asegurarnos de obtener valores diferentes para target cada vez que juguemos, usamos rand.Seed para aleatorizar el generador de números aleatorios según la hora actual. El argumento 100 en rand.Intn nos proporcionará un número dentro del rango de 0 a 100. Luego, usaremos un bucle for para comenzar a recopilar adivinanzas del jugador.

      La función fmt.Scanf nos proporciona un medio para leer las entradas del usuario en una variable que elijamos. Se requiere un verbo de cadena de formato que convierta la entrada del usuario al tipo que esperamos. Aquí %d significa que esperamos un int y pasamos la dirección de la variable guess de modo que fmt.Scanf pueda establecer esa variable. Después de manejar cualquier error de análisis, usamos dos instrucciones if para comparar la adivinanza del usuario con el valor target. El string que muestran, junto con bool, controla el mensaje que se presenta al jugador y si el juego se cerrará.

      Estas instrucciones if ocultan el hecho de que el rango de valores con los que se compara la variable están todos relacionados de alguna manera. También puede ser difícil, a simple vista, saber si faltó alguna parte del rango. En el siguiente ejemplo se vuelve a refactorizar el ejemplo anterior para usar una instrucción switch en su lugar:

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

      Con esto, se mostrará un resultado similar al siguiente:

      Output

      Enter a guess: 25 Too low! Enter a guess: 28 Too high! Enter a guess: 27 You win!

      En esta versión del juego de adivinanzas, se sustituyó el bloque de instrucciones if por una instrucción switch. Se omite el argumento de la expresión de switch, ya que solo nos interesa recopilar los condicionales juntos utilizando switch. Cada cláusula case contiene una expresión diferente que compara guess con target. Como la primera vez que sustituimos las instrucciones if por switch, ya no necesitamos las instrucciones continue porque solo se ejecutará una cláusula case. Por último, la cláusula default se encarga del caso en el que guess == target, ya que cubrimos todos los demás valores posibles con las otras dos cláusulas case.

      En los ejemplos que vimos hasta el momento, se ejecutará exactamente una instrucción caso. De vez en cuando, es posible que desee combinar los comportamientos de varias cláusulas case. Las instrucciones switch proporcionan otra palabra clave para lograr este comportamiento.

      Fallthrough

      A veces, querrá volver a utilizar el código que otra cláusula case contiene. En estos casos, es posible solicitar que Go ejecute el cuerpo de la siguiente cláusula case enumerada usando la palabra clave fallthrough. En el siguiente ejemplo, se modifica nuestro ejemplo anterior de sabores de helado para reflejar con mayor precisión nuestro entusiasmo por el helado de fresa:

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

      Veremos el siguiente resultado:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! strawberry is great! I've never tried banana before

      Como ya lo observamos antes, definimos un segmento string para representar los sabores e iterar este usando un bucle for. La instrucción switch aquí es idéntica a la que vimos antes, pero se agrega la clave fallthrough al final de la cláusula case para “strawberry”. Esto hará que Go ejecute el cuerpo de case “strawberry”:, imprimiendo primero la cadena strawberry is my favorite!. Cuando este encuentre fallthrough, ejecutará el cuerpo de la cláusula case siguiente. Esto hará que el cuerpo de case “vanilla”, “chocolate”: se ejecute e imprima strawberry is great!.

      Los desarrolladores de Go no utilizan la palabra clave fallthrough a menudo. Normalmente, la reutilización del código mediante fallthrough se puede obtener de mejor manera definiendo una función con el código común. Por estas razones, generalmente no se recomienda utilizar fallthrough.

      Conclusión

      Las instrucciones switch nos ayudan a transmitir, a otros desarrolladores que leen nuestro código, que una serie de comparaciones están de alguna manera relacionadas entre sí. Hacen que sea mucho más fácil añadir comportamientos diferentes cuando un nuevo caso se añade en el futuro y permite garantizar que cualquier cosa que se haya olvidado se maneje de manera adecuada también con cláusulas default. La próxima vez que tenga que escribir varias instrucciones if que impliquen todas la misma variable, intente reescribirla con una instrucción switch, le resultará más sencillo volver a trabajar cuando llegue el momento de considerar algún otro valor alternativo.

      Si desea obtener más información acerca del lenguaje de programación de Go, consulte toda la serie sobre Cómo realizar codificaciones en Go.



      Source link

      Использование оператора switch в Go


      Введение

      Условные выражения дают программистам возможность предписывать программам производить определенные действия, если условие выполняется, и другое действие, если условие не выполняется. Нам часто нужно сравнивать определенную переменную с разными возможными значениями и выполнять разные действия для разных результатов. Это можно реализовать, используя только операторы if. Однако написание программного обеспечения предусматривает необходимость не только делать так, чтобы все работало, но и показывать свои намерения себе и другим разработчикам. switch — это альтернативный условный оператор, с помощью которого удобно показывать действия программ Go в ситуациях с разными возможными вариантами.

      Все, что можно написать с помощью оператора switch, можно написать и с помощью операторов if. В этом обучающем руководстве мы рассмотрим несколько примеров того, что может делать оператор switch, как оно может заменить операторы if, и в каких случаях его лучше применять.

      Структура оператора switch

      Оператор 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")
          }
      }
      

      Результат будет выглядеть следующим образом:

      Output

      chocolate 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")
              }
          }
      }
      

      Результат выглядит так же:

      Output

      chocolate 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

      Операторы 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
          }
      }
      

      Результат зависит от случайного числа и от того, как хорошо вы играете в игру. Вот пример результатов одного игрового сеанса:

      Output

      Enter 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
              }
          }
      }
      

      Результат выглядит примерно следующим образом:

      Output

      Enter 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 имеет еще одно ключевое слово для этой цели.

      Fallthrough

      Иногда нам необходимо повторно использовать код, содержащийся в другом выбирающем предложении. В таких случаях можно указать 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")
              }
          }
      }
      

      Результат будет выглядеть примерно так:

      Output

      chocolate 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.



      Source link