10.1 字符串介绍

Go 语言中可以使用反引号或者双引号来定义字符串。反引号表示原生的字符串,即不进行转义。

  • 双引号:字符串使用双引号括起来,其中的相关的转义字符将被替换。例如:
    • str := "Hello World! \n Hello Gopher! \n"
      输出:
      Hello World! 
      Hello Gopher!
      
  • 反引号:字符串使用反引号括起来,其中的相关的转义字符不会被替换。例如:
    • str :=  `Hello World! \n Hello Gopher! \n` 
      输出:
      Hello World! \nHello Gopher! \n
      

双引号中的转义字符被替换,而反引号中原生字符串中的 \n 会被原样输出。

Go 语言中的string类型是一种值类型,存储的字符串是不可变的,如果要修改string内容需要将string转换为[]byte或[]rune,并且修改后的string内容是重新分配的。那么byte和rune的区别是什么(下面写法是type别名):

type byte = uint8
type rune = int32

从上面的定义中我们可清楚看到两者的区别。而string类型的零值是为长度为零的字符串,即空字符串 ""。

一般的比较运算符(==、!=、=、>)通过在内存中按字节比较来实现字符串的对比。你可以通过函数 len() 来获取字符串所占的字节长度,例如:len(str)。

字符串的内容(纯字节)可以通过标准索引法来获取,在中括号 [] 内写入索引,索引从 0 开始计数:字符串 str 的第 1 个字节:str[0] 第 i 个字节:str[i - 1] 最后 1 个字节:str[len(str)-1]

需要注意的是,在Go语言代码使用 UTF-8 编码,同时标识符也支持 Unicode 字符。在标准库 unicode 包中,提供了对 Unicode 相关编码、解码的支持。而UTF8编码由Go语言之父Ken Thompson和Rob Pike共同发明的,现在已经是Unicode的标准。

Go语言默认使用UTF-8编码,对Unicode的支持非常好。但这也带来一个问题,也就是很多资料中提到的“获取字符串长度”的问题。内置的len()函数获取的是每个字符的UTF-8编码的长度和,而不是直接的字符数量。

package main
import (
	"fmt"
	"unicode/utf8"
)
func main() {
	s := "其实就是rune"
	fmt.Println(len(s))                    // "16"
	fmt.Println(utf8.RuneCountInString(s)) // "8"
}

字符串含有中文等字符,我们可以看到每个中文字符的索引值相差3。下面代码同时说明了在for range循环处理字符时,不是按照字节的方式来处理的。v其实际上是一个rune类型值。实际上,Go语言的range循环在处理字符串的时候,会自动隐式解码UTF8字符串。

package main
import (
	"fmt"
)
func main() {
	s := "Go语言四十二章经"
	for k, v := range s {
		fmt.Printf("k:%d,v:%c == %d\n", k, v, v)
	}
}
程序输出:
k:0,v:G == 71
k:1,v:o == 111
k:2,v:语 == 35821
k:5,v:言 == 35328
k:8,v:四 == 22235
k:11,v:十 == 21313
k:14,v:二 == 20108
k:17,v:章 == 31456
k:20,v:经 == 32463

注意事项:

获取字符串中某个字节的地址的行为是非法的,例如:&str[i]。