私は単純化された染色体を表現しようとしています。これは N 個の塩基で構成され、それぞれが の 1 つにしかなりません{A, C, T, G}
。
列挙型を使用して制約を形式化したいと思いますが、Go で列挙型をエミュレートする最も慣用的な方法は何だろうと思っています。
言語仕様からの引用: 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とは別の型にしたい場合。
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
事実上列挙型のようになりました。パッケージ内でのみ、新しいインスタンスを定義できます。
ここには多くの良い答えがあると確信しています。しかし、私は列挙型を使用した方法を追加することを考えました
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 で使用する慣用的な方法の 1 つです。
編集:
定数を使用して列挙する別の方法を追加する
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)
}
このような使用例では、JSON 文字列にマーシャリングできるように文字列定数を使用すると便利な場合があります。次の例で[]Base{A,C,G,T}
は、 にマーシャリングされ["adenine","cytosine","guanine","thymine"]
ます。
type Base string
const (
A Base = "adenine"
C = "cytosine"
G = "guanine"
T = "thymine"
)
を使用するiota
と、値は整数にマーシャリングされます。次の例で[]Base{A,C,G,T}
は、 にマーシャリングされ[0,1,2,3]
ます。
type Base int
const (
A Base = iota
C
G
T
)
両方のアプローチを比較する例を次に示します。
https://stackoverflow.com/a/17989915/863651をリファクタリングして、もう少し読みやすくしました。
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
}