O que é a soma de tipos e como implementá-la em Go?
sobes.tech IA
Resposta da IA
A soma de tipos (ou união etiquetada, união disjuntiva) é um tipo de dados que pode assumir o valor de uma de várias opções predefinidas. Ao contrário do produto de tipos (estruturas), onde o valor contém todos os campos simultaneamente, a soma de tipos contém apenas um dos valores possíveis.
Em Go, não há suporte direto para somas de tipos como em linguagens como Haskell ou Rust (enum). A soma de tipos pode ser emulada de várias maneiras:
-
Interfaces e afirmação de tipo (Type Assertion):
Criar uma interface que todas as opções possíveis implementem. O valor da soma de tipos será essa interface, e para determinar a opção concreta, usa-se afirmação de tipo ou
type switch.package main import "fmt" // Shape - interface que representa a soma de tipos type Shape interface { Area() float64 } // Circle - uma das opções type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } // Rectangle - outra opção type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { shapes := []Shape{Circle{Radius: 5}, Rectangle{Width: 3, Height: 4}} for _, s := range shapes { // Uso de type switch para determinar a opção switch v := s.(type) { case Circle: fmt.Printf("Círculo com raio %.2f, área: %.2f\n", v.Radius, v.Area()) case Rectangle: fmt.Printf("Retângulo com dimensões %.2f x %.2f, área: %.2f\n", v.Width, v.Height, v.Area()) default: fmt.Println("Forma desconhecida") } } } -
Estruturas com flags booleanos (raramente usadas):
A estrutura contém campos para todas as opções possíveis e flags booleanos para indicar qual opção está ativa. É inseguro e difícil de manter.
package main import "fmt" type Result struct { Value int // Campo para resultado bem-sucedido Err error // Campo para erro IsValue bool // Flag indicando se Value está ativo IsErr bool // Flag indicando se Err está ativo } func Process(input int) Result { if input > 0 { return Result{Value: input * 2, IsValue: true} } return Result{Err: fmt.Errorf("número negativo: %d", input), IsErr: true} } func main() { res1 := Process(10) if res1.IsValue { fmt.Printf("Resultado: %d\n", res1.Value) } else if res1.IsErr { fmt.Printf("Erro: %v\n", res1.Err) } res2 := Process(-5) if res2.IsValue { fmt.Printf("Resultado: %d\n", res2.Value) } else if res2.IsErr { fmt.Printf("Erro: %v\n", res2.Err) } } -
Estruturas com valor nulo para campos não ativos (frequentemente usadas para Optional/Result):
A estrutura contém campos para todas as opções possíveis, mas apenas um deles será não nulo. Funciona bem com ponteiros ou tipos que têm um valor "nulo" bem definido.
package main import "fmt" // Option - emulação de Some/None do tipo opcional type Option struct { Value *int // Não nulo se houver valor } // None cria um valor Option nulo func None() Option { return Option{} } // Some cria um Option com valor func Some(val int) Option { return Option{Value: &val} } func main() { opt1 := Some(10) if opt1.Value != nil { fmt.Printf("Valor: %d\n", *opt1.Value) } else { fmt.Println("Sem valor") } opt2 := None() if opt2.Value != nil { fmt.Printf("Valor: %d\n", *opt2.Value) } else { fmt.Println("Sem valor") } }
A maneira mais idiomática e segura de emular somas de tipos em Go é usar interfaces e type switch. Isso garante que apenas uma das opções esteja presente e fornece segurança de tipo ao trabalhar com ela.