나는 N 개의 염기로 구성된 단순화 된 염색체를 나타내려고 노력하고 있는데, 각각은 염기 중 하나만 될 수 있습니다 {A, C, T, G}
.
열거 형으로 제약 조건을 공식화하고 싶지만 열거 형을 에뮬레이트하는 가장 관용적 인 방법이 무엇인지 궁금합니다.
나는 N 개의 염기로 구성된 단순화 된 염색체를 나타내려고 노력하고 있는데, 각각은 염기 중 하나만 될 수 있습니다 {A, C, T, G}
.
열거 형으로 제약 조건을 공식화하고 싶지만 열거 형을 에뮬레이트하는 가장 관용적 인 방법이 무엇인지 궁금합니다.
답변:
언어 사양에서 인용 : Iota
상수 선언 내에서 미리 선언 된 식별자 iota는 연속적인 형식화되지 않은 정수 상수를 나타냅니다. 예약어 const가 소스에 나타날 때마다 0으로 재설정되고 각 ConstSpec 후에 증가합니다. 관련 상수 세트를 구성하는 데 사용할 수 있습니다.
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)
ExpressionList 내에서 각 iota의 값은 각 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
)
이 마지막 예는 비어 있지 않은 마지막 표현식 목록의 암시 적 반복을 활용합니다.
따라서 코드는
const (
A = iota
C
T
G
)
또는
type Base int
const (
A Base = iota
C
T
G
)
기본이 int와 다른 유형이되도록하려는 경우.
Ord(Base)
에 국한되지 않습니다 0..3
하지만 기본 숫자 형식과 같은 한계가있다. 언어 디자인 선택이며 안전과 성능 사이의 타협입니다. Base
입력 된 값을 터치 할 때마다 항상 "안전한"런타임 검사를 고려하십시오 . 또는 어떻게 하나의 '오버 플로우'행동을 정의해야합니다 Base
를 arithmetics과 가치를 ++
와 --
? 기타
iota + 1
0에서 시작하지 않으 려면 사용할 수 있습니다.
jnml의 답변을 참조하면 Base 유형을 전혀 내 보내지 않으면 서 Base 유형의 새 인스턴스를 방지 할 수 있습니다 (즉, 소문자로 작성). 필요한 경우 기본 유형을 반환하는 메서드가있는 내보내기 가능한 인터페이스를 만들 수 있습니다. 이 인터페이스는베이스를 다루는 외부 기능에서 사용될 수 있습니다.
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
}
기본 패키지 내부 a.Baser
는 사실상 열거 형과 같습니다. 패키지 내부에서만 새 인스턴스를 정의 할 수 있습니다.
base
메소드 리시버로만 사용되는 경우에는 메소드가 완벽 해 보입니다 . 귀하의 경우 a
패키지 유형의 매개 변수를 복용하는 기능을 노출했다 base
, 그것은 위험 할 것입니다. 실제로 사용자는 리터럴 값 42를 사용하여 호출 할 base
수 있습니다.이 값은 int로 캐스팅 될 수 있으므로 함수가 허용 합니다. 이를 방지하기 위해 만들 base
을 struct
: type base struct{value:int}
. 문제 : 더 이상베이스를 상수로 선언 할 수없고 모듈 변수 만 선언 할 수 있습니다. 그러나 42는 결코 base
그런 유형 으로 캐스팅되지 않습니다 .
당신은 그렇게 할 수 있습니다 :
type MessageType int32
const (
TEXT MessageType = 0
BINARY MessageType = 1
)
이 코드로 컴파일러는 열거 형의 유형을 확인해야합니다
그것은 사용하는 위의 예 것은 사실 const
및 iota
이동에 원시적 열거를 나타내는 가장 관용적 가지 방법이 있습니다. 그러나 Java 또는 Python과 같은 다른 언어에서 볼 수있는 유형과 유사한 완전한 기능을 갖춘 열거 형을 만드는 방법을 찾고 있다면 어떨까요?
파이썬에서 문자열 열거 형처럼 보이고 느끼기 시작하는 객체를 만드는 매우 간단한 방법은 다음과 같습니다.
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())
}
이 시점에서 작동하지만 색상을 반복적으로 정의해야하는 방식이 마음에 들지 않을 수 있습니다. 이 시점에서 그것을 없애고 싶다면 구조체에 태그를 사용하고 그것을 반영하기 위해 멋진 반영을 할 수는 있지만 대부분의 사람들을 덮기에 충분하기를 바랍니다.
나는 우리가 여기에 좋은 대답을 많이 가지고 있다고 확신합니다. 그러나 열거 형을 사용하는 방식을 추가하려고 생각했습니다.
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)
}
다음은 열거가 많은 경우에 유용한 예입니다. Golang의 구조를 사용하고 객체 지향 원칙을 사용하여 깔끔한 작은 묶음으로 모두 묶습니다. 새로운 열거가 추가되거나 삭제 될 때 기본 코드는 변경되지 않습니다. 과정은 다음과 같습니다
enumeration items
: EnumItem를 . 정수 및 문자열 유형이 있습니다.enumeration
의 목록으로 정의 enumeration items
: Enumenum.Name(index int)
: 주어진 인덱스의 이름을 반환합니다.enum.Index(name string)
: 주어진 인덱스의 이름을 반환합니다.enum.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"}}}