我目前正在学习Go rosalind problems(基本上是一堆与生物信息学相关的代码katas)。
我目前正代表一种类型为:
的DNA链type DNAStrand struct {
dna byte[]
}
我最初的原因是封装了字节切片,所以我知道它只包含代表核苷酸的字节:'A', 'C', 'G', 'T'
。我意识到这显然没有保证,因为我可以这样做:
DNAStrand{[]byte("foo bar")}
并且不再保证我的dna链包含一个只包含来自这四个字节的元素的字节数组。
由于我的struct只包含一个字节数组,因此更好/更理想:
type DNAStrand []byte
或者让类型包含dna链更好吗?何时使用这两种方法中的任何一种都有任何经验法则吗?
答案 0 :(得分:11)
以你的具体例子,我可能会做这样的事情:
type neucleotide char // unexported type users can't construct their own.
type DNAStrand []neucleotide // because users can't construct their own
// nucleotides they also can't construct their
// own DNAStrands.
const (
// These are exported values so they can use these nucleotides to construct a
// DNAStrand with.
A nucleotide = 'A'
C nucleotide = 'C'
G nudleotide = 'G'
T nucleotide = 'T'
)
// This function allows them to actually construct a DNAstrand with a list of
// nucleotides from the constants above.
func New(nts ...nucleotide) DNAStrand {
return nts
}
由于核苷酸类型未导出,用户无法自行构建。您在导出的consts中提供了它们唯一允许的实例,因此没有用户可以提供自己的新核苷酸。
答案 1 :(得分:2)
具有零字段的结构非常方便。有许多领域的结构更方便。只有一个领域的结构有点特殊,我想不出一个合理的“好”的情况,在哪里使用它们 - 即使它们在野外经常被看到。我是一个人,不要使用它们。
无论如何,如果你真的需要关于DNAStrand
切片内容的更严格/防弹安全性 - 那么就可以使用单个字段结构并为这个/这样的命名类型定义一个参数检查setter方法。 / p>
在这种情况下,如果稍后从其他包中使用该定义,则无法使用package unsafe模数来规避检查并获得与您的DNAStrand{[]byte("foo bar")}
示例等效的结果。
答案 2 :(得分:1)
我使用type DNAStrand []byte
因为它很简单,因为我可以使用正则表达式。我可能会使用初始化函数来检查每个字节是否在ACGT中。
var validDNAStrandPat = regexp.MustCompile("[ACTG]*")
func DNAStrandForString(s string) DNAStrand {
if !validDNAStrandPat.Match(s) {
panic("Invalid DNA Strand.")
}
return DNAStrand([]byte(s))
}