menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right the-way-to-go_ZH_CN chevron_right eBook chevron_right 04.6.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    04.6.md
    4.1 KB / 2024-07-16 23:14:27
        # 4.6 字符串
    
    字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其它包括 XML 和 JSON 在内,也都使用该编码。由于该编码对占用字节长度的不定性,Go 中的字符串里面的字符也可能根据需要占用 1 至 4 个字节(示例见[第 4.6 节](04.6.md)),这与其它语言如 C++、Java 或者 Python 不同(Java 始终使用 2 个字节)。Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。
    
    字符串是一种值类型,且值不可变,即创建某个文本后你无法再次修改这个文本的内容;更深入地讲,字符串是字节的定长数组。
    
    Go 支持以下 2 种形式的字面值:
    
    - 解释字符串:
    
    	该类字符串使用双引号括起来,其中的相关的转义字符将被替换,这些转义字符包括:
    
    	- `\n`:换行符
    	- `\r`:回车符
    	- `\t`:tab 键
    	- `\u` 或 `\U`:Unicode 字符
    	- `\\`:反斜杠自身
    
    - 非解释字符串:
    
    	该类字符串使用反引号括起来,支持换行,例如:
    
    		`This is a raw string \n` 中的 `\n\` 会被原样输出。
    
    和 C/C++不一样,Go 中的字符串是根据长度限定,而非特殊字符 `\0`。
    
    `string` 类型的零值为长度为零的字符串,即空字符串 `""`。
    
    一般的比较运算符(`==`、`!=`、`<`、`<=`、`>=`、`>`)通过在内存中按字节比较来实现字符串的对比。你可以通过函数 `len()` 来获取字符串所占的字节长度,例如:`len(str)`。
    
    字符串的内容(纯字节)可以通过标准索引法来获取,在中括号 `[]` 内写入索引,索引从 0 开始计数:
    
    - 字符串 `str` 的第 1 个字节:`str[0]`
    - 第 `i` 个字节:`str[i - 1]`
    - 最后 1 个字节:`str[len(str)-1]`
    
    需要注意的是,这种转换方案只对纯 ASCII 码的字符串有效。
    
    **注意事项** 获取字符串中某个字节的地址的行为是非法的,例如:`&str[i]`。
    
    **字符串拼接符 `+`**
    
    两个字符串 `s1` 和 `s2` 可以通过 `s := s1 + s2` 拼接在一起。
    
    `s2` 追加在 `s1` 尾部并生成一个新的字符串 `s`。
    
    你可以通过以下方式来对代码中多行的字符串进行拼接:
    
    ```go
    str := "Beginning of the string " +
    	"second part of the string"
    ```
    
    由于编译器行尾自动补全分号的缘故,加号 `+` 必须放在第一行。
    
    拼接的简写形式 `+=` 也可以用于字符串:
    
    ```go
    s := "hel" + "lo,"
    s += "world!"
    fmt.Println(s) //输出 “hello, world!”
    ```
    
    在循环中使用加号 `+` 拼接字符串并不是最高效的做法,更好的办法是使用函数 `strings.Join()`([第 4.7.10 节](04.7.md)),有没有更好的办法了?有!使用字节缓冲(`bytes.Buffer`)拼接更加给力([第 7.2.6 节](07.2.md))!
    
    在[第 7 章](07.0.md),我们会讲到通过将字符串看作是字节 (`byte`) 的切片 (slice) 来实现对其标准索引法的操作。会在[第 5.4.1 节](05.4.md) 中讲到的 `for` 循环只会根据索引返回字符串中的纯字节,而在[第 5.4.4 节](./05.4.md)(以及[第 7.6.1 节](07.6.md) 的示例)将会展示如何使用 for-range 循环来实现对 Unicode 字符串的迭代操作。在下一节,我们会学习到许多有关字符串操作的函数和方法,同时 `fmt` 包中的 `fmt.Sprint(x)` 也可以格式化生成并返回你所需要的字符串([第 4.4.3 节](04.3.md))。
    
    **练习 4.6** [count_characters.go](exercises/chapter_4/count_characters.go)
    
    创建一个用于统计字节和字符 (rune) 的程序,并对字符串 `asSASA ddd dsjkdsjs dk` 进行分析,然后再分析 `asSASA ddd dsjkdsjsこん dk`,最后解释两者不同的原因(提示:使用 `unicode/utf8` 包)。
    
    ## 链接
    
    - [目录](directory.md)
    - 上一节:[基本类型和运算符](04.5.md)
    - 下一节:[strings 和 strconv 包](04.7.md)
    
    
    links
    file_download