如何在Go中表示可选字符串?

jam*_*her 9 string null variant go optional

我希望建模一个可以有两种可能形式的值:缺席或字符串.

执行此操作的自然方式是with Maybe String,or Optional<String>,or string option等.但是,Go没有这样的变体类型.

然后我想,在Java,C等之后,替代方案将是可空性,或者nil在Go中.但是,nil不是stringGo 中的类型成员.

搜索,然后我想使用该类型*string.这可能有效,但看起来很尴尬(例如,我不能采用字符串文字的地址,就像我可以获取结构文字的地址一样).

在Go中模拟这样一个值的惯用方法是什么?

Ain*_*r-G 8

你可以使用类似的东西sql.NullString,但我个人会坚持*string.至于尴尬,你不可能sp := &"foo"不幸的是.但有一个解决方法:

func strPtr(s string) *string {
    return &s
}
Run Code Online (Sandbox Code Playgroud)

呼叫strPtr("foo")应该内联,所以它是有效的&"foo".

另一种可能性是使用new:

sp := new(string)
*sp = "foo"
Run Code Online (Sandbox Code Playgroud)

  • @MichalČizmazia 语言,例如 Haskell,使用 `Maybe` (另一个名称是 `Optional`),并且在正常情况下不使用异常进行错误处理。事实上,“可选”类型与异常无关,而是编译时检查(与异常相反)。 (4认同)
  • 谢谢。指针解决方案似乎确实和我将得到的一样好,这令人失望。为什么,为什么在21世纪,语言仍然没有变体类型/和类型/ ADT。 (2认同)

icz*_*cza 8

合理的解决方案是使用*stringAinar-G提到的.这个其他答案详细说明了获取指向值的指针的可能性(int64但同样也适用string).包装器是另一种解决方案.

使用正好 string

可选string表示string加1特定值(或状态),表示"不是字符串"(但是a null).

这1个特定值可以存储(信号)在另一个变量(例如bool),你可以包装string和bool成struct和我们到达的包装,但这并不适合进入的情况下,"只用string"(但仍然是一个可行的解决方案

如果我们只想坚持一个string,我们可以从一个string类型的可能值中取出一个特定的值(由于长度不受限制,它具有"无穷大"可能值(或者可能是因为它必须是一个int但是都是右)),我们可以将这个特定值命名为null值,这个值意味着"不是字符串".

最方便的指示值null是零值string,即空string:"".指定此null元素具有以下便利:无论何时创建string变量而未明确指定初始值,它都将使用初始化"".此外,当从其map值中查询元素时,如果该键不在,string则也将产生.""map

该解决方案适用于许多现实使用案例.string例如,如果可选项应该是某个人的姓名,则空白string并不代表有效的人名,因此您不应该首先允许这样做.

当然,当empty string表示string类型变量的有效值时,可能会出现这种情况.对于这些用例,我们可以选择其他值.

在Go中,a string实际上是一个只读的字节片.请参阅Go中的文章帖子字符串,字节,符文和字符,详细解释了这一点.

所以a string是一个字节片,在有效文本的情况下是UTF-8编码的字节.假设你想在你的可选中存储一个有效的文本string(如果你不想,那么你可以只使用一个[]byte可以有nil值的代替),你可以选择一个string代表无效的UTF-8字节序列的值,从而你赢了甚至不得不妥协以从可能的值中排除有效文本.最短的无效UTF-8字节序列仅为1字节,例如0xff(还有更多).注意:您可以使用该utf8.ValidString()函数来判断string值是否为有效文本(有效的UTF-8编码字节序列).

你可以把这个特殊的价值变成const:

const Null = "\xff"
Run Code Online (Sandbox Code Playgroud)

做这个短也意味着检查一个是否string等于这个是非常快的.
按照这个惯例,你已经有一个可选的string,也允许空string.

在Go Playground尝试一下.

const Null = "\xff"

func main() {
    fmt.Println(utf8.ValidString(Null)) // false

    s := Null
    fmt.Println([]byte(s)) // [255]
    fmt.Println(s == Null) // true
    s = "notnull"
    fmt.Println(s == Null) // false
}
Run Code Online (Sandbox Code Playgroud)

  • 但是,使用此方法,我们可能会丢失 s 可能为 null 的上下文。 (3认同)