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

Cesar Gimenes