A logo showing the text blog.marcnuri.com
English
Inicio»Go»Enums en Go: Un enfoque alternativo

Entradas Recientes

  • Fabric8 Kubernetes Client 7.2.0 está disponible!
  • Conectarse a un servidor MCP con JavaScript y AI SDK
  • Conectarse a un servidor MCP con JavaScript y LangChain.js
  • El Futuro de las Herramientas para Desarrolladores en la era de la IA
  • Conectarse a un servidor Model Context Protocol (MCP) con Java y LangChain4j

Categorías

  • Antiguo
  • Front-end
  • Go
  • Herramientas
  • Industria y negocios
  • Inteligencia Artificial
  • Java
  • JavaScript
  • Operaciones
  • Personal
  • Proyectos personales

Archivos

  • mayo 2025
  • abril 2025
  • marzo 2025
  • febrero 2025
  • enero 2025
  • diciembre 2024
  • noviembre 2024
  • agosto 2024
  • junio 2024
  • mayo 2024
  • abril 2024
  • marzo 2024
  • febrero 2024
  • enero 2024
  • diciembre 2023
  • noviembre 2023
  • octubre 2023
  • septiembre 2023
  • agosto 2023
  • julio 2023
  • junio 2023
  • mayo 2023
  • abril 2023
  • marzo 2023
  • febrero 2023
  • enero 2023
  • diciembre 2022
  • noviembre 2022
  • octubre 2022
  • agosto 2022
  • julio 2022
  • mayo 2022
  • marzo 2022
  • febrero 2022
  • enero 2022
  • diciembre 2021
  • noviembre 2021
  • octubre 2021
  • septiembre 2021
  • agosto 2021
  • julio 2021
  • diciembre 2020
  • octubre 2020
  • agosto 2020
  • junio 2020
  • mayo 2020
  • marzo 2020
  • febrero 2020
  • enero 2020
  • noviembre 2019
  • octubre 2019
  • julio 2019
  • diciembre 2018
  • agosto 2018
  • julio 2018
  • junio 2018
  • mayo 2018
  • marzo 2018
  • febrero 2018
  • noviembre 2017
  • octubre 2017
  • agosto 2017
  • julio 2017
  • enero 2017
  • julio 2016
  • enero 2016
  • diciembre 2015
  • noviembre 2015
  • diciembre 2014
  • marzo 2014
  • febrero 2011
  • junio 2008
  • mayo 2008
  • abril 2008
  • enero 2008
  • junio 2007
  • mayo 2007
  • abril 2007
  • marzo 2007

Enums en Go: Un enfoque alternativo

2020-02-11 en Go etiquetado Go por Marc Nuri | Última actualización: 2025-02-19
English version

Introducción

Los programadores de Go a menudo echan de menos los tipos de enumeraciones (enum) integrados que proporcionan lenguajes como Java o C#. En Go, los desarrolladores suelen emular los enums definiendo un nuevo tipo personalizado y un conjunto de constantes relacionadas (a menudo usando el identificador iota).

En este artículo, te mostraré cómo emular los enums en Go usando tipos personalizados y constantes y cómo mejorarlos con métodos y generación de código.

Consejo

¿Qué es un enum? Una enumeración (enum) es un tipo distinto que consiste en un conjunto de constantes llamadas elementos o enumeradores. El tipo enum restringe las variables a solo aquellos valores definidos en la enumeración. Los enums son útiles para definir un conjunto fijo de valores relacionados.

¿Por qué Go no tiene enums?

La filosofía de diseño de Go enfatiza la simplicidad y el minimalismo. Mientras que los enums tradicionales proporcionan seguridad de tipo y un conjunto fijo de valores, Go opta por la flexibilidad de las declaraciones de constantes. Este enfoque se alinea bien con el diseño general del lenguaje y te permite definir un conjunto claro de valores relacionados.

Usar constantes como enums

El patrón más común para emular enums en Go es definir un nuevo tipo personalizado (generalmente basado en int) y un conjunto de constantes relacionadas. El identificador iota se utiliza a menudo para crear una secuencia de valores relacionados.

Aquí tienes un ejemplo de cómo definir un tipo personalizado y constantes para representar un conjunto limitado de lenguajes de programación:

language.go
package main

import "fmt"

type Language int

const (
    Unknown Language = iota // 0
    Go                      // 1
    Java                    // 2
    Python                  // 3
    JavaScript              // 4
)

func main() {
    var lang Language = Go
    fmt.Printf("The language is: %v\n", lang) // Output: The language is: 1
}

En este ejemplo, definimos un nuevo tipo personalizado Language basado en int y un conjunto de constantes relacionadas.

Consejo

¿Qué es iota? El identificador iota es un identificador predeclarado que representa constantes de integer sucesivas. Se reinicia a 0 cada vez que se entra en el bloque const e incrementa en 1 para cada declaración de constante subsiguiente.

Ventajas de usar constantes como enums:

  • Seguridad de tipado: El tipo personalizado Language restringe las variables a solo aquellos valores definidos en la enumeración.
  • Legibilidad: Las constantes proporcionan nombres descriptivos para cada valor, haciendo que el código sea más legible.
  • Unicidad: El identificador iota garantiza que cada constante sea única, evitando la reutilización accidental de valores.
  • Mantenibilidad: Las constantes son fáciles de actualizar y mantener, lo que te permite agregar o eliminar valores según sea necesario sin tener que actualizar cada constante individualmente.

Agregar comportamiento a los enums con métodos

Si bien las constantes pueden representar un conjunto fijo de valores relacionados, carecen de la capacidad de definir comportamiento. Una ventaja de declarar un tipo personalizado es que puedes adjuntarle métodos.

Aquí tienes un ejemplo de cómo agregar un método String al tipo Language para devolver el nombre del lenguaje:

language.go
func (l Language) String() string {
  return [...]string{"Unknown", "Go", "Java", "Python", "JavaScript"}[l]
}

func main() {
  var lang Language = Go
  fmt.Printf("The language is: %v\n", lang) // Output: The language is: Go
}

Este sencillo enfoque usando el método String() facilita la conversión del tipo Language a una cadena mucho más legible.

Mejorar los enums con generación de código

A medida que tu enumeración crece, mantener la lista de constantes y los métodos asociados puede volverse engorroso y propenso a errores. Si agregas o eliminas valores del enum, debes recordar actualizar la lista de constantes y cualquier método asociado en consecuencia.

Una forma de abordar este problema es mediante el uso de herramientas de generación de código como stringer para generar automáticamente el método String para tu tipo personalizado.

Aquí te muestro cómo puedes usar stringer para generar el método String para el tipo Language:

Comienza instalando la herramienta stringer:

bash
go get golang.org/x/tools/cmd/stringer@latest

A continuación, agrega una directiva //go:generate a tu archivo fuente para ejecutar la herramienta stringer automáticamente con go generate:

language.go
package main

import "fmt"

//go:generate stringer -type=Language -linecomment
type Language int

const (
    Unknown Language = iota
    Go                      // Golang
    Java
    Python
    JavaScript
)

func main() {
  var lang Language = Go
  fmt.Printf("The language is: %v\n", lang) // Output: The language is: Golang
}

Al ejecutar go generate ./... en el mismo directorio que tu código fuente, stringer generará el método String para el tipo Language en un nuevo archivo language_string.go.

bash
go generate

Este enfoque facilita el proceso de agregar o eliminar valores de tu enum, ya que el método String se actualiza automáticamente cada vez que ejecutas go generate.

Manejar la serialización JSON con enums

Go representará tu enum como su valor entero subyacente si serializas una estructura que contiene tu enum por defecto. Para personalizar la representación JSON de tu enum, puedes implementar las interfaces json.Marshaler y json.Unmarshaler.

Aquí tienes un ejemplo de cómo implementar las interfaces json.Marshaler y json.Unmarshaler para el tipo Language:

language.go
import (
    "encoding/json"
    "fmt"
)

func (l Language) MarshalJSON() ([]byte, error) {
    return json.Marshal(l.String())
}

func (l *Language) UnmarshalJSON(data []byte) error {
    var s string
    if err := json.Unmarshal(data, &s); err != nil {
        return err
    }
    switch s {
    case "Go":
        *l = Go
    case "Java":
        *l = Java
    case "Python":
        *l = Python
    case "JavaScript":
        *l = JavaScript
    default:
        *l = Unknown
    }
    return nil
}

El método MarshalJSON se utiliza para serializar el tipo Language. El método UnmarshalJSON se utiliza para deserializar el tipo Language.

Al implementar estos métodos, puedes controlar cómo se representa tu enum en formato JSON.

Limitaciones y compromisos

Si bien usar constantes como enums es un patrón común en Go, tiene algunas limitaciones:

  • Seguridad de tipado: A pesar de tener un tipo distinto, nada impide a un programador convertir un entero arbitrario a tu tipo enum.
  • Exhaustividad: No hay una forma integrada de garantizar que una instrucción switch cubra todos los valores del enum.
  • Verbosidad: Definir un tipo personalizado y constantes para cada enum puede ser engorroso, especialmente para enums grandes.
  • Duplicidad: Cuando se requiere un comportamiento adicional (como el parseo de una cadena), es posible que termines escribiendo un código similar para cada tipo enum. Consulta el método UnmarshalJSON en la sección anterior para ver un ejemplo.

Conclusión

Si bien Go no proporciona enums integrados, puedes emularlos eficazmente utilizando tipos personalizados y constantes. Al añadir métodos a tu tipo personalizado y utilizar herramientas de generación de código como stringer, puedes mejorar tus enums con comportamiento adicional y simplificar el mantenimiento.

Siguiendo estos patrones, puedes incorporar eficazmente la funcionalidad de enum en tus proyectos de Go, proporcionando seguridad de tipo y un conjunto claro de valores relacionados para hacer que tu código sea robusto y legible.

Twitter iconFacebook iconLinkedIn iconPinterest iconEmail icon

Navegador de artículos
Cómo Inicializar un Nuevo Proyecto Go con MódulosEntendiendo las funciones variádicas en Go
© 2007 - 2025 Marc Nuri