我试图表示一个简化的染色体,它由N个碱基组成,每个碱基只能是{a, C, T, G}中的一个。
我想用枚举形式化约束,但我想知道在Go中模拟枚举的最惯用的方式是什么。
我试图表示一个简化的染色体,它由N个碱基组成,每个碱基只能是{a, C, T, G}中的一个。
我想用枚举形式化约束,但我想知道在Go中模拟枚举的最惯用的方式是什么。
当前回答
下面是一个示例,当有许多枚举时,它将被证明是有用的。它使用了Golang中的结构,并借鉴了面向对象原则(Object Oriented Principles),将它们紧密地捆绑在一起。添加或删除新的枚举时,底层代码都不会更改。流程如下:
定义枚举项的枚举结构:EnumItem。它有一个整数和字符串类型。 将枚举定义为枚举项列表:Enum 为枚举构建方法。其中包括: 枚举。Name(index int):返回给定索引的名称。 枚举。Index(name string):返回给定索引的名称。 枚举. last():返回最后一个枚举的索引和名称 添加枚举定义。
下面是一些代码:
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"}}}
其他回答
我相信我们有很多好的答案。但是,我只是想以使用枚举类型的方式添加
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())
}
这是迄今为止我们创建枚举类型并在Go中使用的惯用方法之一。
编辑:
添加另一种使用常量进行枚举的方法
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)
}
此外,这是在一个字节的一个位置存储不同角色的一种非常有效的方法,其中第一个值被设置为1,位移动了一个iota。
package main
import "fmt"
const (
isCaptain = 1 << iota
isTrooper
isMedic
canFlyMars
canFlyJupiter
canFlyMoon
)
func main() {
var roles byte = isCaptain | isMedic | canFlyJupiter
//Prints a binary representation.
fmt.Printf("%b\n", roles)
fmt.Printf("%b\n", isCaptain)
fmt.Printf("%b\n", isTrooper)
fmt.Printf("%b\n", isMedic)
fmt.Printf("Is Captain? %v\n", isCaptain&roles == isCaptain)
fmt.Printf("Is Trooper? %v", isTrooper&roles == isTrooper)
}
的确,上面使用const和iota的例子是在Go中表示原始枚举的最惯用的方式。但是,如果您正在寻找一种方法来创建功能更全的枚举,类似于您在其他语言(如Java或Python)中看到的类型,该怎么办呢?
在Python中创建一个看起来像字符串enum的对象的一个非常简单的方法是:
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)
}
假设您还需要一些实用程序方法,如Colors.List()和Colors.Parse("red")。你的颜色更复杂,需要一个结构。然后你可以这样做:
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())
}
在这一点上,当然它可以工作,但你可能不喜欢你必须重复定义颜色。如果此时您想消除这种情况,您可以在结构上使用标签并进行一些花哨的反射来设置它,但希望这足以覆盖大多数人。
对于这样的用例,使用字符串常量可能很有用,这样就可以将其封送到JSON字符串中。在下例中,[]碱基{A,C,G,T}将被编组为["腺嘌呤","胞嘧啶","鸟嘌呤","胸腺嘧啶"]。
type Base string
const (
A Base = "adenine"
C = "cytosine"
G = "guanine"
T = "thymine"
)
当使用iota时,值被封送成整数。在下面的例子中,[]基数{A,C,G,T}将被封送到[0,1,2,3]。
type Base int
const (
A Base = iota
C
G
T
)
下面是一个比较两种方法的例子:
https://play.golang.org/p/VvkcWvv-Tvj
你可以这样做:
type MessageType int32
const (
TEXT MessageType = 0
BINARY MessageType = 1
)
使用此代码,编译器应该检查枚举类型