2013-01-20 42 views
315

我試圖表示一個簡化的染色體,它由N個鹼基組成,每個鹼基只能是{A, C, T, G}之一。什麼是在Go中表示枚舉的習慣用法?

我想用enum正式確定約束條件,但是我想知道在Go中模擬枚舉最常用的方法是什麼。

+3

的類型在他們表示爲常量走標準封裝。請參閱http://golang.org/pkg/os/#pkg-constants –

+2

相關:http:// stackoverflow。com/questions/14236263/when-should-a-type-be-a-struct-containing-another-type-and-when-should-it- – lbonn

+0

[Golang:Creating a Constant Type and Restricting (類型的值](http://stackoverflow.com/questions/37385007/golang-creating-a-constant-type-and-restricting-the-types-values) – icza

回答

443

從語言規範引用:Iota

內的恆定聲明中,預聲明標識符IOTA表示連續無類型整數常數。只要保留字const在源中出現並在每個ConstSpec後遞增,它就被重置爲0。它可用於構建一組相關的常量:

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) 

在一個表達式列表,每個絲毫的值是相同的,因爲它是每個常量實現後僅遞增:

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 
) 

這最後一個例子利用了最後一個非空表達式列表的隱式重複。


所以,如果你想要基地,以從int單獨類型的代碼可能會像

const (
     A = iota 
     C 
     T 
     G 
) 

type Base int 

const (
     A Base = iota 
     C 
     T 
     G 
) 

+11

很好的例子(我沒有記得確切的iota行爲 - 當它增加時 - 來自規範)。我個人喜歡給一個枚舉類型,所以它可以作爲參數,字段等進行類型檢查。 – mna

+9

非常有趣@jnml。但我有點失望,靜態類型檢查似乎是鬆散的,例如沒有任何東西阻止我使用從未存在的Base n°42:http://play.golang.org/p/oH7eiXBxhR – Deleplace

+3

Go沒有概念數字子範圍類型,例如Pascal's有,所以'Ord(Base)'不限於'0..3',但是它的底層數字類型有相同的限制。這是一種語言設計選擇,在安全性和性能之間妥協。每次觸摸「Base」類型的值時,請考慮「安全」運行時間限制檢查。或者應該如何爲算術和'++'和'--'定義'Base'值的'溢出'行爲?等 – zzzz

57

參考jnml的答案,您可以根本不導出Base類型(即將其寫成小寫字母)來阻止Base類型的新實例。如果需要的話,你可能會做出有返回一個基本類型,所以該接口可以從與基地應對外部函數中使用的方法可輸出接口,即

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 
} 

主包裏面的a.Baser實際上就像一個枚舉。 只有在包中可以定義新的實例。

+7

您的方法似乎適用於「base」僅用作方法接收器的情況。如果你的'a'包暴露了一個帶'base'類型參數的函數,那麼它就會變得危險。事實上,用戶可以用字面值42來調用它,因爲函數可以被轉換爲int,所以函數將接受它作爲「base」。爲了防止出現這種情況,請將'base'設爲'struct':'type base struct {value:int}'。問題:你不能將base聲明爲常量,只能聲明模塊變量。但是42永遠不會被轉換爲這種類型的「基礎」。 – Niriel

+1

@metakeule我試圖理解你的例子,但你在變量名中的選擇使它變得非常困難。 – anon58192932

13

從Go 1.4開始,go generate工具與stringer命令一起引入,使您的枚舉變得易於調試和打印。

1

你可以把它這樣:

type MessageType int32 

const (
    TEXT MessageType = 0 
    BINARY MessageType = 1 
) 

有了這個代碼編譯器應該檢查枚舉

+2

常量通常以正常駝峯書寫,並非全部大寫。最初的大寫字母意味着變量被導出,這可能是也可能不是你想要的。 – 425nesp

+1

我注意到在Go源代碼中有一個混合,有時常量都是大寫,有時它們是camelcase。你有參考規格嗎? –

+0

@JeremyGailor我認爲425nesp只是指出,開發人員使用它們作爲_unexported_常量,所以使用camelcase。如果開發人員確定它應該導出,那麼可以隨意使用全部大寫或大寫字母,因爲沒有確定的偏好。 請參閱[Golang代碼審查建議](https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps)和 [有效的常量部分](https://golang.org/doc/) effective_go.html#constants) – waynethec

相關問題