gpt4 book ai didi

go - 字符串值和字符串文字之间的区别

转载 作者:IT王子 更新时间:2023-10-29 02:01:31 26 4
gpt4 key购买 nike

根据此golang关于字符串的博客文章(https://blog.golang.org/strings),有一行指出“... 字符串值可以包含任意字节;正如我们在本篇文章中所展示的,字符串文字始终包含UTF-8文本因为它们没有字节级转义。”

有什么不同?

最佳答案

这种区别取决于字符串文字和字符串值的Go language specification中的定义:

String literal: A string literal represents a string constant obtained from concatenating a sequence of characters.

String value: A string value is a (possibly empty) sequence of bytes.



以及在以UTF-8文本编码的源文件中表示源代码的要求:

Source code representation: Source code is Unicode text encoded in UTF-8.



最关键的是,请注意,字符串文字被定义为常量,因此其值完全在编译时定义。

将有效的Go源文件集视为符合语言规范的那些文件。根据定义,此类源文件必须使用有效的UTF-8进行编码。由于字符串字面量的值是在编译时从源文件的内容中得知的,因此我们可以通过构造看到任何字符串字面量都必须包含有效的UTF-8文本。

如果我们忽略字节级转义序列,则可以进一步看到,字符串二进制文本在所得二进制文件中的编译输出也必须包含有效的UTF-8,因为它是从源文件中的UTF-8值编译而来的。

字节序列?概括

但是,字符串 defined是字节序列1,因此不需要它们本身包含有效的UTF-8。此类非UTF-8文本可能来自于程序在编译时定义的字符串文字之外的输入值,例如通过套接字或本地管道接收的数据,从文件中读取的数据或包含字节级转义的字符串文字序列。

1如博客文章所述,在大多数情况下,此字节序列可以被视为 byte slice ( []byte)。但是,这并不是严格正确的,因为基础实现不使用 slice 。字符串是不可变的,不需要单独跟踪其容量。调用 cap(str),其中 str的类型为 string is an error

字节级转义序列

字节级转义序列提供了一种使用UTF-8表示形式对非UTF-8值进行编码的机制。这样的序列允许以UTF-8格式表示任意字节,以生成有效的Go源文件并满足语言规范。

例如,字节序列 b2 bd(此处字节表示为以空格分隔的两位十六进制数字)是 not valid UTF-8。尝试使用UTF-8解码器解码此字节序列将产生错误:

var seq = "\xb2\xbd"
fmt.Println("Is 'seq' valid UTF-8 text?", utf8.Valid([]byte(seq)))
$ go run ./main.go
Is 'seq' valid UTF-8 text? false

因此,尽管可以将这样的字节序列存储在Go的字符串中,但无法直接在Go源文件中表示。任何这样做的源文件都是无效的Go,词法分析器将拒绝它(请参见下文)。

反斜杠转义序列提供了一种机制,用于将该字节字符串分解为满足工具链的有效UTF-8表示形式。解释后的Go字符串文字 "\xb2\xbd"使用ASCII字符序列表示字符串,该字符串可以UTF-8表示。编译时,将解析此序列,以在编译的输出中生成一个字符串,其中包含字节序列 b2 bd

例子

我将提供一个工作示例,以更具体地说明这一点。由于我们将生成无效的源文件,因此我无法立即使用Go游乐场。我在机器上使用了go工具链。工具链为 go version go1.11 darwin/amd64

考虑以下简单的Go程序,其中可以为字符串 myStr指定值。为了方便起见,我们用所需的字节替换空白(字符串序列 20 20 20后的字节序列 my value:)。这使我们在以后分解二进制文件时可以轻松找到编译后的输出。

package main

import "fmt"

func main() {
myStr := "my value: "
fmt.Println(myStr)
}

我使用了十六进制编辑器,将无效的UTF-8字节序列 b2 bd插入 myStr的空格的最后字节中。下面的表示形式;为简洁起见,省略了其他内容:
00000030: 203a 3d20 22b2 bd20 220a 0966 6d74 2e50   := ".. "..fmt.P

尝试构建此文件将导致错误:
$ go build ./test.go
# command-line-arguments
./test.go:6:12: invalid UTF-8 encoding

如果我们在编辑器中打开文件,它将以自己的方式解释字节(可能是特定于平台的),并在保存时发出有效的UTF-8。在此基于OS X的系统上,使用 vim,序列被解释为Unicode U + 00B2 U + 00BD或 ²½。这满足了编译器的要求,但是源文件和因此编译的二进制文件现在包含的字节序列与最初的字节序列不同。下面的代码转储显示序列 c2 b2 c2 bd,源文件的十六进制转储也是如此。 (请参见第1行的最后两个字节和第2行的前两个字节。)
$ gobjdump -s -j __TEXT.__rodata test | grep -A1 "my value"                                                                                         
10c4c50 63746f72 796d7920 76616c75 653ac2b2 ctorymy value:..
10c4c60 c2bd206e 696c2065 6c656d20 74797065 .. nil elem type

为了恢复原始的字节序列,我们可以这样更改字符串定义:
myStr := "my value: \xb2\xbd"

转储由编辑器生成的源文件会产生有效的UTF-8序列 5c 78 62 32 5c 78 62 64,即ASCII字符 \xb2\xbd的UTF-8编码:
00000030: 203a 3d20 226d 7920 7661 6c75 653a 205c   := "my value: \
00000040: 7862 325c 7862 6422 0a09 666d 742e 5072 xb2\xbd"..fmt.Pr

然而,通过构建此源文件生成的二进制文件表明,编译器已将此字符串文字转换为包含所需的 b2 bd序列(第四列的最后两个字节):
10c48b0 6d792076 616c7565 3a20b2bd 6e6f7420  my value: ..not

关于go - 字符串值和字符串文字之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52135054/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com