¿Qué es la suma de tipos y cómo implementarla en Go?
sobes.tech AI
Respuesta de la IA
La suma de tipos (o unión etiquetada, unión disyuntiva) es un tipo de datos que puede tomar el valor de una de varias opciones predefinidas. A diferencia del producto de tipos (estructuras), donde el valor contiene todos los campos simultáneamente, la suma de tipos contiene solo uno de los posibles valores.
En Go no hay soporte directo para sumas de tipos como en lenguajes como Haskell o Rust (enum). La suma de tipos se puede emular de varias maneras:
-
Interfaces y afirmación de tipo (Type Assertion):
Crear una interfaz que implementen todas las opciones posibles. El valor de la suma de tipos será esa interfaz, y para determinar la opción concreta se usa afirmación de tipo o
type switch.package main import "fmt" // Shape - interfaz que representa la suma de tipos type Shape interface { Area() float64 } // Circle - una de las opciones type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } // Rectangle - otra opción 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 la opción switch v := s.(type) { case Circle: fmt.Printf("Círculo con radio %.2f, área: %.2f\n", v.Radius, v.Area()) case Rectangle: fmt.Printf("Rectángulo con dimensiones %.2f x %.2f, área: %.2f\n", v.Width, v.Height, v.Area()) default: fmt.Println("Forma desconocida") } } } -
Estructuras con banderas booleanas (rara vez usadas):
La estructura contiene campos para todas las opciones posibles y banderas booleanas para indicar cuál opción está activa. Es inseguro y difícil de mantener.
package main import "fmt" type Result struct { Value int // Campo para resultado exitoso Err error // Campo para error IsValue bool // Bandera que indica si Value está activo IsErr bool // Bandera que indica si Err está activo } 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("Error: %v\n", res1.Err) } res2 := Process(-5) if res2.IsValue { fmt.Printf("Resultado: %d\n", res2.Value) } else if res2.IsErr { fmt.Printf("Error: %v\n", res2.Err) } } -
Estructuras con valor nulo para campos no activos (usado frecuentemente para Opcional/Resultado):
La estructura contiene campos para todas las opciones posibles, pero solo uno será no nulo. Funciona bien con punteros o tipos con un valor "nulo" definido.
package main import "fmt" // Option - emulación de Some/None del tipo opcional type Option struct { Value *int // No nulo si hay valor } // None crea un valor nulo de Option func None() Option { return Option{} } // Some crea un Option con valor func Some(val int) Option { return Option{Value: &val} } func main() { opt1 := Some(10) if opt1.Value != nil { fmt.Printf("Hay valor: %d\n", *opt1.Value) } else { fmt.Println("No hay valor") } opt2 := None() if opt2.Value != nil { fmt.Printf("Hay valor: %d\n", *opt2.Value) } else { fmt.Println("No hay valor") } }
El método más idiomático y seguro para emular sumas de tipos en Go es usar interfaces y type switch. Esto garantiza que solo una opción esté presente y proporciona seguridad de tipos al trabajar con ella.