首页 > 编程笔记 > Go语言笔记 阅读:18

Go语言字符串的用法(新手必看)

Go语言中的字符串是基本的数据类型,不是引用或指针类型。字符串是只读的字节切片(byte slice),以静态方式存储,可以使用 len() 函数获取长度。字符串的 byte 数组中可以存放任意数据。

初始化字符串以后,不能像操作字符数组那样直接修改字符串的内容,因为编译器会将字符串的字符分配到只读内存段。如果需要修改,则只能重新指定新值,这样它的存储地址就会变为新值的地址,而不是去修改原来在内存中存储的值。

我们可以把变量强制转换成字节类型的切片,这样 Go语言就会为切片变量重新分配内存,并将原始字符串的内容复制到切片上,如此操作之后,就能脱离只读内存的限制。

Go 语言字符串的声明和初始化方式与其他类型是一样的,示例代码如下:
var str string = "abcd" //声明及初始化
str := "abcd" //自动推导类型
字符串可以使用双引号(")定义,也可以使用反引号(`)定义。使用反引号定义最大的优点是支持跨行。

Go语言遍历字符串

遍历字符串有以下三种方法。

1) 借助len()遍历字符串

根据 len() 函数求出字符串的长度,然后使用下标遍历字符串。

如果字符串中包含中文,使用此方法会出现乱码。原因是这种方式是基于 1 字节遍历的,而一个汉字在 UTF-8 编码中对应的是 3 字节。示例代码如下:
str := "a~学Go!"
//输出:str[0] = a,str[1] = ~,str[2] = å,str[3] = ,str[4] = ¦,str[5] = G,str[6] = o,str[7] = !
for i := 0; i < len(str); i++ {
    fmt.Printf("str[%d] = %c\n", i, str[i])
}

2) 使用for…range的方式遍历字符串

该方法基于字符来遍历字符串,因此,即使字符串中包含中文字符,也可以成功遍历且不会出现乱码。但是因为每个汉字占 3 字节,所以字符串的下标不是我们想要的结果。

示例代码如下:
//输出:str[0] = a,str[1] = ~,str[2] = 学,str[5] = G,str[6] = o,str[7] = !
for index, value := range str {
    fmt.Printf("str[%d] = %c\n", index, value)
}

3) 使用切片的方式遍历字符串

因为字符串是特殊的切片,所以可以将字符串先转换为 [ ]rune,再作为切片进行遍历,这样在有汉字的情况下就不会出现乱码,即使有下标,也与中文的顺序完全匹配。

示例代码如下:
str1 := []rune(str)
//输出:str1[0] = a,str1[1] = ~,str1[2] = 学,str1[3] = G,str1[4] = o,str1[5] = !
for i := 0; i < len(str1); i++ {
    fmt.Printf("str1[%d] = %c\n", i, str1[i])
}

Go语言字符串的长度问题

使用 len() 函数获取的长度是字节数,当字符串中含有汉字时,按照字节长度计算会将一个汉字计算为 3 字节,也就是说,一个汉字的长度是 3,而我们预期的长度是 1。

要解决此问题,可以使用下表所列举的四种方法,它们都能正确地计算字符串长度:

表:计算字符串长度的四种方法
序号 方法 示例
1 将字符串转换为切片,再使用内置 len() 函数计算长度 len([]rune(str))
2 使用 bytes.Count 计算长度 bytes.Count([]byte(str), nil) - 1
3 使用 strings.Count 计算长度 strings.Count(str, "") - 1
4 使用 utf8.RuneCountInString 计算长度 utf8.RuneCountInString(str)

Go语言字符串的数据结构

Go 语言默认的编码是 UTF-8,那么字符串的数据结构长什么样呢?

我们知道,字符串是一系列字符的集合,只有知道内存中的起始地址才能找到字符串的第一个字符,想要正确读取整个字符串还需要知道它的结束位置,那么它又该在哪里结束呢?

在 C语言中,可以通过在内容末尾添加特定的标识符 \0 来表示字符串的结束,但这样做的缺点是限定了内容中不能再使用标识符 \0,否则会产生意料不到的结果。Go 语言在 C语言的基础上做了改进,它将字符串的长度项放置在内容的开头。

在 Go语言中,字符串是一个只读的字节序列,它内部使用了两个属性:起始地址和长度。因为 Go语言使用 UTF-8 编码,一个字符可能占用 1~4 字节,所以字符串的结束位置可以通过起始地址加上长度得到。这样,在读取字符串时,程序就知道从哪个地址开始读取,以及需要读取多少字节了。

注意此长度并非字符数,而是字节数。我们一直在强调,Go语言中没有专门的字符类型,有些编程语言的字符串是由字符组成的,而 Go语言的字符串由单个字节连接而成。

字符串在内存中的数据结构示意图如下图所示:


图 1 字符串在内存中的数据结构示意图

相关文章