¿Qué es una forma idiomática de representar enum en Go?
Estoy tratando de 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.
6 answers
Citando las especificaciones del idioma: Iota
Dentro de una declaración constante, el identificador predeclared iota representa constantes enteras sucesivas sin tipo. Se restablece a 0 cada vez que la palabra reservada const aparece en la fuente y se incrementa después de cada ConstSpec. Se puede usar para construir un conjunto de constantes relacionadas:
const ( // iota is reset to 0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
const (
a = 1 << iota // a == 1 (iota has been reset)
b = 1 << iota // b == 2
c = 1 << iota // c == 4
)
const (
u = iota * 42 // u == 0 (untyped integer constant)
v float64 = iota * 42 // v == 42.0 (float64 constant)
w = iota * 42 // w == 84 (untyped integer constant)
)
const x = iota // x == 0 (iota has been reset)
const y = iota // y == 0 (iota has been reset)
Dentro de una ExpressionList, el valor de cada iota es el mismo porque solo se incrementa después de cada ConstSpec:
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0
bit1, mask1 // bit1 == 2, mask1 == 1
_, _ // skips iota == 2
bit3, mask3 // bit3 == 8, mask3 == 7
)
Este último ejemplo explota la repetición implícita de la última lista de expresiones no vacía.
Así que su código podría ser como
const (
A = iota
C
T
G
)
O
type Base int
const (
A Base = iota
C
T
G
)
Si desea que bases sea un tipo separado de int.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-20 17:07:34
Refiriéndose 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úsculas). Si es necesario, puede hacer una interfaz exportable que tenga un método que devuelva un tipo base, de modo que esta interfaz pueda usarse en funciones del exterior que traten con 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 a puede definir nuevas instancias.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-02 07:09:22
A partir de Go 1.4, la herramienta go generate
se ha introducido junto con el stringer
comando que hace que su enumeración sea fácilmente depurable e imprimible.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-05 12:01:29
Puedes hacerlo así:
type MessageType int32
const (
TEXT MessageType = 0
BINARY MessageType = 1
)
Con este compilador de código debe comprobar el tipo de enumeración
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-21 11:05:08
Es cierto que los ejemplos anteriores de usar const
y iota
son las formas más idiomáticas de representar enum primitivos en Go. Pero, ¿qué pasa si estás buscando una manera de crear una enumeración más completa similar al tipo que verías en otro lenguaje como Java o Python?
Una forma muy sencilla de crear un objeto que comience a verse y sentirse como una enumeración de cadena 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 desea 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 usted podría hacer algo un poco 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 colores repetitivamente. Si en este punto desea eliminar eso, podría usar etiquetas en su estructura y hacer un poco de reflexión elegante para configurarlo, pero espero que esto sea suficiente para cubrir a la mayoría de las personas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-19 22:54:01
Estoy seguro de que tenemos muchas buenas respuestas aquí. Pero, solo pensé en agregar la forma en que he utilizado tipos enumerados
package main
import "fmt"
type Enum interface {
name() string
ordinal() int
values() *[]string
}
type GenderType uint
const (
MALE = iota
FEMALE
)
var genderTypeStrings = []string{
"MALE",
"FEMALE",
}
func (gt GenderType) name() string {
return genderTypeStrings[gt]
}
func (gt GenderType) ordinal() int {
return int(gt)
}
func (gt GenderType) values() *[]string {
return &genderTypeStrings
}
func main() {
var ds GenderType = MALE
fmt.Printf("The Gender is %s\n", ds.name())
}
Esta es, con mucho, una de las formas idiomáticas que podríamos crear tipos Enumerados y usar en Go.
Editar:
Añadiendo otra forma de usar constantes para enumerar
package main
import (
"fmt"
)
const (
// UNSPECIFIED logs nothing
UNSPECIFIED Level = iota // 0 :
// TRACE logs everything
TRACE // 1
// INFO logs Info, Warnings and Errors
INFO // 2
// WARNING logs Warning and Errors
WARNING // 3
// ERROR just logs Errors
ERROR // 4
)
// Level holds the log level.
type Level int
func SetLogLevel(level Level) {
switch level {
case TRACE:
fmt.Println("trace")
return
case INFO:
fmt.Println("info")
return
case WARNING:
fmt.Println("warning")
return
case ERROR:
fmt.Println("error")
return
default:
fmt.Println("default")
return
}
}
func main() {
SetLogLevel(INFO)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-30 08:10:14