Tutorial

Como escrever instruções switch em Go

Published on February 13, 2020
Português
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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


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!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more