Sobes.tech
Senior

¿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:

  1. 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")
    		}
    	}
    }
    
  2. 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)
    	}
    }
    
  3. 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.