什么时候类型应该是一个包含另一种类型的结构?什么时候应该只是“扩展”(?)那种类型?

时间:2013-01-09 13:26:31

标签: types struct go

我目前正在学习Go rosalind problems(基本上是一堆与生物信息学相关的代码katas)。

我目前正代表一种类型为:

的DNA链
type DNAStrand struct {
    dna byte[]
}

我最初的原因是封装了字节切片,所以我知道它只包含代表核苷酸的字节:'A', 'C', 'G', 'T'。我意识到这显然没有保证,因为我可以这样做:

DNAStrand{[]byte("foo bar")}

并且不再保证我的dna链包含一个只包含来自这四个字节的元素的字节数组。

由于我的struct只包含一个字节数组,因此更好/更理想:

type DNAStrand []byte

或者让类型包含dna链更好吗?何时使用这两种方法中的任何一种都有任何经验法则吗?

3 个答案:

答案 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))
}