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

我希望对一个值进行建模,该值可以有两种可能的形式:不存在或字符串。

这样做的自然方法是使用Maybe String、 或Optional<String>、 或string option等。但是,Go 没有这样的变体类型。

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

搜索,然后我想到使用 type *string。这可以工作,但看起来很尴尬(例如,我不能以与获取结构文字地址相同的方式获取字符串文字的地址)。

在 Go 中对这样的值进行建模的惯用方法是什么?


RISEBY
浏览 195回答 3
3回答

倚天杖

一个合乎逻辑的解决方案是使用*stringAinar-G 提到的。另一个答案详细说明了获取指向值的指针的可能性(int64但同样适用string)。包装器是另一种解决方案。仅使用 string可选string表示string加 1 的特定值(或状态)表示“不是字符串”(而是 a null)。这1个特定值可以存储(信号)在另一个变量(例如bool),你可以包装string和bool成struct和我们到达的包装,但这并不适合进入的情况下,“只用string”(但仍然是一个可行的解决方案)。如果我们只想坚持 a string,我们可以从string类型的可能值中取出 1 个特定值(它具有“无穷大”可能值,因为长度不受限制(或者可能是因为它必须是 anint但仅此而已)对)),我们可以将这个特定的值命名为null值,该值的意思是“不是字符串”。最方便的指示值null是 的零值string,即空string: ""。指定这个null元素很方便,每当你创建一个string没有明确指定初始值的变量时,它都会被初始化""。还从一个查询的元素时map,其值是string也将产生""如果键不在map。该解决方案适合许多现实生活中的用例。string例如,如果可选项应该是一个人的名字,那么空string并不意味着一个有效的人名,所以你首先不应该允许它。当然,可能存在空string值确实表示string类型变量的有效值的情况。对于这些用例,我们可以选择另一个值。在 Go 中, astring实际上是一个只读的字节片。请参阅博客文章Go 中的字符串、字节、符文和字符,其中详细解释了这一点。所以 astring是一个字节切片,它是有效文本情况下的 UTF-8 编码字节。假设你想在你的可选中存储一个有效的文本string(如果你不想,那么你可以使用一个[]byte可以有一个nil值的代替),你可以选择一个string代表无效 UTF-8 字节序列的值,因此你赢了甚至不必妥协以从可能的值中排除有效文本。例如,最短的无效 UTF-8 字节序列仅为 1 个字节0xff(还有更多)。注意:您可以使用该utf8.ValidString()函数来判断一个string值是否为有效文本(有效的 UTF-8 编码字节序列)。您可以将此特殊值设为 a const:const Null = "\xff"这么短也意味着检查 a 是否string等于 this会非常快。按照这个约定,你已经有了一个可选的string,它也允许空的string.在Go Playground上试一试。const Null = "\xff"func main() {&nbsp; &nbsp; fmt.Println(utf8.ValidString(Null)) // false&nbsp; &nbsp; s := Null&nbsp; &nbsp; fmt.Println([]byte(s)) // [255]&nbsp; &nbsp; fmt.Println(s == Null) // true&nbsp; &nbsp; s = "notnull"&nbsp; &nbsp; fmt.Println(s == Null) // false}

千万里不及你

你可以使用类似的东西sql.NullString,但我个人会坚持使用*string. 至于尴尬,确实不能只是sp := &"foo"不幸。但是有一个解决方法:func strPtr(s string) *string {&nbsp; &nbsp; return &s}调用strPtr("foo")应该被内联,所以它是有效的&"foo"。另一种可能性是使用new:sp := new(string)*sp = "foo"

心有法竹

对于接口类型,您可以使用更自然的赋值语法。var myString interface{} // used as type <string>myString = nil // nil is the default -- and indicates 'empty'myString = "a value"在引用值时,通常需要类型断言来明确检查。// checked type assertionif s, exists := myString.(string); exists {&nbsp; &nbsp; useString(s)}此外,由于stringers,在某些上下文中将自动处理“可选”类型——这意味着您不需要显式转换该值。该fmt软件包使用此功能:fmt.Println("myString:",myString) // prints the value (or "<nil>")警告分配给值时没有类型检查。在某些方面,这是一种比处理指针更简洁的方法。但是,因为这使用了接口类型,所以它不限于持有特定的底层类型。风险在于您可能会无意中分配不同的类型——这将nil与上述条件中的处理方式相同。下面是使用接口进行赋值的演示:var a interface{} = "hello"var b = a // b is an interface toob = 123 // assign a different typefmt.Printf("a: (%T) %v\n", a, a)fmt.Printf("b: (%T) %v\n", b, b)输出:a:(字符串)你好b: (int) 123请注意,接口是通过重复分配的,因此a和b是不同的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go