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

Última modificação