Ik probeer een vereenvoudigd chromosoom te vertegenwoordigen, dat bestaat uit n-basen, die elk alleen een van {A, C, T, G}
kunnen zijn.
Ik zou graag de beperkingen met een ENUM formaliseren, maar ik vraag me af wat de meest idiomatische manier om een ENUM te emuleren, in gang is.
Antwoord 1, Autoriteit 100%
citeren uit de taalspecificaties: iota
Binnen een constante verklaring vertegenwoordigt de voorafgekeurde identificator IOTA opeenvolgende niet-getaleerde gehele constanten. Het wordt gereset naar 0 wanneer het gereserveerde woord const verschijnt in de bron en stappen na elke CONSTSPEC. Het kan worden gebruikt om een reeks gerelateerde constanten te construeren:
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)
Binnen een expressionist, is de waarde van elke IOTA hetzelfde omdat het na elke CONSTPEC alleen wordt verhoogd:
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
)
Dit laatste voorbeeld maakt gebruik van de impliciete herhaling van de laatste niet-lege lijst met uitdrukkingen.
Dus je code zou kunnen zijn als
const (
A = iota
C
T
G
)
of
type Base int
const (
A Base = iota
C
T
G
)
als je wilt dat basen een apart type zijn van int.
Antwoord 2, autoriteit 13%
Verwijzend naar het antwoord van jnml, zou je nieuwe instanties van het Base-type kunnen voorkomen door het Base-type helemaal niet te exporteren (d.w.z. schrijf het in kleine letters). Indien nodig kunt u een exporteerbare interface maken met een methode die een basistype retourneert. Deze interface kan worden gebruikt in functies van buitenaf die te maken hebben met Bases, d.w.z.
package a
type base int
const (
A base = iota
C
T
G
)
type Baser interface {
Base() base
}
// every base must fulfill 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
}
In het hoofdpakket is a.Baser
nu in feite een opsomming.
Alleen binnen het a-pakket kunt u nieuwe instanties definiëren.
Antwoord 3, autoriteit 6%
Je kunt het zo maken:
type MessageType int32
const (
TEXT MessageType = 0
BINARY MessageType = 1
)
Met deze code moet compiler het type enum controleren
Antwoord 4, autoriteit 5%
Het is waar dat de bovenstaande voorbeelden van het gebruik van const
en iota
de meest idiomatische manieren zijn om primitieve opsommingen in Go weer te geven. Maar wat als u op zoek bent naar een manier om een uitgebreidere opsomming te maken, vergelijkbaar met het type dat u in een andere taal zoals Java of Python zou zien?
Een heel eenvoudige manier om een object te maken dat eruitziet en aanvoelt als een string-enum in Python zou zijn:
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)
}
Stel dat u ook enkele hulpprogramma’s wilt, zoals Colors.List()
en Colors.Parse("red")
. En je kleuren waren complexer en moesten een structuur zijn. Dan zou je iets als dit kunnen doen:
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())
}
Op dat moment werkt het zeker, maar misschien vind je het niet leuk hoe je herhaaldelijk kleuren moet definiëren. Als je dat op dit moment wilt elimineren, kun je tags op je struct gebruiken en wat fantasieën doen om het in te stellen, maar hopelijk is dit genoeg om de meeste mensen te dekken.
Antwoord 5, autoriteit 3%
Vanaf Go 1.4 is de go generate
-tool geïntroduceerd samen met de stringer
-commando waarmee uw opsomming gemakkelijk kan worden opgespoord en afgedrukt.
Antwoord 6, autoriteit 3%
Er is een manier met struct namespace.
Het voordeel is dat alle enum-variabelen onder een specifieke naamruimte staan om vervuiling te voorkomen.
Het probleem is dat we alleen var
konden gebruiken en niet const
type OrderStatusType string
var OrderStatus = struct {
APPROVED OrderStatusType
APPROVAL_PENDING OrderStatusType
REJECTED OrderStatusType
REVISION_PENDING OrderStatusType
}{
APPROVED: "approved",
APPROVAL_PENDING: "approval pending",
REJECTED: "rejected",
REVISION_PENDING: "revision pending",
}
Antwoord 7, autoriteit 2%
Ik weet zeker dat we hier veel goede antwoorden hebben. Maar ik dacht er gewoon aan om de manier toe te voegen waarop ik opgesomde typen heb gebruikt
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())
}
Dit is verreweg een van de idiomatische manieren waarop we Enumerated-typen kunnen maken en in Go kunnen gebruiken.
Bewerken:
Een andere manier toevoegen om constanten te gebruiken om op te sommen
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)
}
Antwoord 8
Voor een use-case als deze kan het handig zijn om een stringconstante te gebruiken, zodat deze kan worden omgezet in een JSON-string. In het volgende voorbeeld wordt []Base{A,C,G,T}
gemarshaleerd naar ["adenine","cytosine","guanine","thymine"]
.
type Base string
const (
A Base = "adenine"
C = "cytosine"
G = "guanine"
T = "thymine"
)
Bij gebruik van iota
worden de waarden gegroepeerd in gehele getallen. In het volgende voorbeeld wordt []Base{A,C,G,T}
gemarshald naar [0,1,2,3]
.
type Base int
const (
A Base = iota
C
G
T
)
Hier is een voorbeeld waarin beide benaderingen worden vergeleken:
https://play.golang.org/p/VvkcWvv-Tvj
Antwoord 9
Hier is een voorbeeld dat handig zal zijn als er veel opsommingen zijn. Het maakt gebruik van structuren in Golang en maakt gebruik van objectgeoriënteerde principes om ze allemaal samen te binden in een nette kleine bundel. Geen van de onderliggende code zal veranderen wanneer een nieuwe opsomming wordt toegevoegd of verwijderd. Het proces is:
- Definieer een opsommingsstructuur voor
enumeration items
: EnumItem. Het heeft een geheel getal en een tekenreeks. - Definieer de
enumeration
als een lijst vanenumeration items
: Enum - Bouw methoden voor de opsomming. Er zijn er een aantal opgenomen:
enum.Name(index int)
: retourneert de naam voor de gegeven index.enum.Index(name string)
: retourneert de naam voor de gegeven index.enum.Last()
: retourneert de index en de naam van de laatste opsomming
- voeg uw opsommingsdefinities toe.
Hier is een code:
type EnumItem struct {
index int
name string
}
type Enum struct {
items []EnumItem
}
func (enum Enum) Name(findIndex int) string {
for _, item := range enum.items {
if item.index == findIndex {
return item.name
}
}
return "ID not found"
}
func (enum Enum) Index(findName string) int {
for idx, item := range enum.items {
if findName == item.name {
return idx
}
}
return -1
}
func (enum Enum) Last() (int, string) {
n := len(enum.items)
return n - 1, enum.items[n-1].name
}
var AgentTypes = Enum{[]EnumItem{{0, "StaffMember"}, {1, "Organization"}, {1, "Automated"}}}
var AccountTypes = Enum{[]EnumItem{{0, "Basic"}, {1, "Advanced"}}}
var FlagTypes = Enum{[]EnumItem{{0, "Custom"}, {1, "System"}}}
Antwoord 10
Refactured https://stackoverflow.com/a/17989915/863651 Om het een beetje leesbaar te maken:
package SampleEnum
type EFoo int
const (
A EFoo = iota
C
T
G
)
type IEFoo interface {
Get() EFoo
}
func(e EFoo) Get() EFoo { // every EFoo must fulfill the IEFoo interface
return e
}
func(e EFoo) otherMethod() { // "private"
//some logic
}