Erro difícil com interfaces e switch case em Go
Veja o vídeo falando desse erro no Grupo de Estudos de Golang.
Golang é uma linguagem bem fácil de programar e que tem poucas armadilhas para o programador. A maioria das coisas que podem dar errado são pegas pelo compilador ou por alguma das muitas ferramentas de análise estática que ajudam a manter nosso código quase livre de bugs.
Mas existem situações em que mesmo essas ferramentas tem dificuldade nos alertar porque não da para saber o que o programador queria que fosse o resultado do programa. Isso geralmente acontece usando os recursos mais divertidos da linguagem como switch, interfaces, canais e goroutines.
Erro na ordem do switch
Aqui vamos discutir um erro bem difícil de achar, basicamente a ordem dos cases de um switch esta errada, o maior escopo esta em primeiro lugar fazendo com que o switch sempre pare nele. Para resolver o problema basta mudar a ordem dos cases colocando os casos de menor escopo no início. Mas até ai já foi um tempão debugando código e litros de café. É preciso entender o funcionamento dos recursos da linguagem porque não existe compilador que consiga pegar todos os possíveis erros que um programador inspirado pode cometer.
Veja o exemplo abaixo.
package main
import "fmt"
type comptometer interface {
Sum(a, b int) int
}
type foo struct{}
func (_ foo) Sum(a, b int) int {
return a + b
}
type bar struct{}
func (_ bar) Sum(a, b int) int {
return a + b
}
//
func printType(e comptometer) {
/*
Este switch esta na ordem errada
e vai imprimir sempre "comptometer
interface" e nunca via entrar nos
outros cases do switch. Mova o case
comptometer para o fim do switch
para resolver o bug.
*/
switch e.(type) {
case comptometer:
fmt.Println("comptometer interface")
case *foo:
fmt.Println("ponteiro para foo")
case *bar:
fmt.Println("ponteiro para bar")
}
}
func main() {
var f = &foo{}
printType(f)
var b = &bar{}
printType(b)
}
A instrução switch vai testar caso a caso na ordem em que eles aparecem e saltar no primeiro que satisfazer a ordem. No exemplo a interface comptometer sempre vai satisfazer a condição porque as duas outras structs implementam a função que a interface esta esperando.
Você pode ver o código fonte desse exemplo no nosso repositório do Grupo de Estudos de Golang