[enums] ¿Cuál es una forma idiomática de representar enumeraciones en Go?


Answers

En referencia a la respuesta de jnml, podría evitar nuevas instancias de tipo Base al no exportar el tipo Base en absoluto (es decir, escribirlo en minúscula). Si es necesario, puede crear una interfaz exportable que tenga un método que devuelva un tipo de base, de modo que esta interfaz pueda usarse en funciones externas que se ocupen de Bases, es decir,

package a

type base int

const (
    A base = iota
    C
    T
    G
)


type Baser interface {
    Base() base
}

// every base must fullfill the Baser interface
func(b base) Base() base {
    return b
}


func(b base) OtherMethod()  {
}
package main

import "a"

// func from the outside that handles a.base via a.Baser
// since a.base is not exported, only exported bases that are created within package a may be used, like a.A, a.C, a.T. and a.G
func HandleBasers(b a.Baser) {
    base := b.Base()
    base.OtherMethod()
}


// func from the outside that returns a.A or a.C, depending of condition
func AorC(condition bool) a.Baser {
    if condition {
       return a.A
    }
    return a.C
}

Dentro del paquete principal, a.Baser es efectivamente como una enumeración ahora. Solo dentro del paquete puede definir nuevas instancias.

Question

Intento representar un cromosoma simplificado, que consiste en N bases, cada una de las cuales solo puede ser una de {A, C, T, G} .

Me gustaría formalizar las restricciones con una enumeración, pero me pregunto cuál es la forma más idiomática de emular una enumeración en Go.




Es cierto que los ejemplos anteriores de usar const e iota son las formas más idiomáticas de representar enumeraciones primitivas en Go. Pero, ¿qué sucede si estás buscando una forma de crear una enumeración con más funciones similar a la que verías en otro idioma como Java o Python?

Una forma muy simple de crear un objeto que empiece a verse y sentirse como una cadena de enumeración en Python sería:

package main

import (
    "fmt"
)

var Colors = newColorRegistry()

func newColorRegistry() *colorRegistry {
    return &colorRegistry{
        Red:   "red",
        Green: "green",
        Blue:  "blue",
    }
}

type colorRegistry struct {
    Red   string
    Green string
    Blue  string
}

func main() {
    fmt.Println(Colors.Red)
}

Supongamos que también quiere algunos métodos de utilidad, como Colors.List() y Colors.Parse("red") . Y tus colores eran más complejos y necesitaban ser una estructura. Entonces podrías hacer algo como esto:

package main

import (
    "errors"
    "fmt"
)

var Colors = newColorRegistry()

type Color struct {
    StringRepresentation string
    Hex                  string
}

func (c *Color) String() string {
    return c.StringRepresentation
}

func newColorRegistry() *colorRegistry {

    red := &Color{"red", "F00"}
    green := &Color{"green", "0F0"}
    blue := &Color{"blue", "00F"}

    return &colorRegistry{
        Red:    red,
        Green:  green,
        Blue:   blue,
        colors: []*Color{red, green, blue},
    }
}

type colorRegistry struct {
    Red   *Color
    Green *Color
    Blue  *Color

    colors []*Color
}

func (c *colorRegistry) List() []*Color {
    return c.colors
}

func (c *colorRegistry) Parse(s string) (*Color, error) {
    for _, color := range c.List() {
        if color.String() == s {
            return color, nil
        }
    }
    return nil, errors.New("couldn't find it")
}

func main() {
    fmt.Printf("%s\n", Colors.List())
}

En ese punto, seguro que funciona, pero puede que no te guste cómo tienes que definir los colores de manera repetitiva. Si en este punto quisieras eliminar eso, podrías usar etiquetas en tu estructura y hacer algunos reflejos para configurarlo, pero ojalá esto sea suficiente para la mayoría de las personas.




Related