Golang可能会踩的58个坑之初级篇( 三 )

16.string 类型的值是常量 , 不可更改尝试使用索引遍历字符串,来更新字符串中的个别字符,是不允许的 。
string 类型的值是只读的二进制 byte slice,如果真要修改字符串中的字符,将 string 转为 []byte 修改后,再转为 string 即可:
// 修改字符串的错误示例func main() {x := "text"x[0] = "T"// error: cannot assign to x[0]fmt.Println(x)}// 修改示例func main() {x := "text"xBytes := []byte(x)xBytes[0] = 'T'// 注意此时的 T 是 rune 类型x = string(xBytes)fmt.Println(x)// Text}注意: 上边的示例并不是更新字符串的正确姿势,因为一个 UTF8 编码的字符可能会占多个字节,比如汉字就需要 3~4个字节来存储,此时更新其中的一个字节是错误的 。
更新字串的正确姿势:将 string 转为 rune slice(此时 1 个 rune 可能占多个 byte),直接更新 rune 中的字符
func main() {x := "text"xRunes := []rune(x)xRunes[0] = '我'x = string(xRunes)fmt.Println(x)// 我ext}17.string 与 byte slice 之间的转换当进行 string 和 byte slice 相互转换时,参与转换的是拷贝的原始值 。这种转换的过程,与其他编程语的强制类型转换操作不同,也和新 slice 与旧 slice 共享底层数组不同 。
Go 在 string 与 byte slice 相互转换上优化了两点,避免了额外的内存分配:

  • 在 map[string] 中查找 key 时,使用了对应的 []byte , 避免做 m[string(key)] 的内存分配
  • 使用 for range 迭代 string 转换为 []byte 的迭代:for i,v := range []byte(str) {...}
18.string 与索引操作符对字符串用索引访问返回的不是字符,而是一个 byte 值 。
func main() {x := "ascii"fmt.Println(x[0])// 97fmt.Printf("%T\n", x[0])// uint8}如果需要使用 for range 迭代访问字符串中的字符(unicode code point / rune) , 标准库中有 "unicode/utf8" 包来做 UTF8 的相关解码编码 。另外 utf8string 也有像 func (s *String) At(i int) rune 等很方便的库函数 。
19.字符串并不都是 UTF8 文本string 的值不必是 UTF8 文本,可以包含任意的值 。只有字符串是文字字面值时才是 UTF8 文本,字串可以通过转义来包含其他数据 。
判断字符串是否是 UTF8 文本,可使用 "unicode/utf8" 包中的 ValidString() 函数:
func main() {str1 := "ABC"fmt.Println(utf8.ValidString(str1))// truestr2 := "A\xfeC"fmt.Println(utf8.ValidString(str2))// falsestr3 := "A\\xfeC"fmt.Println(utf8.ValidString(str3))// true// 把转义字符转义成字面值}20.字符串的长度在 Python 中:
data = https://www.huyubaike.com/biancheng/u''print(len(data)) # 1然而在 Go 中:
func main() {char := ""fmt.Println(len(char))// 3}Go 的内建函数 len() 返回的是字符串的 byte 数量,而不是像 Python 中那样是计算 Unicode 字符数 。
如果要得到字符串的字符数 , 可使用 "unicode/utf8" 包中的 RuneCountInString(str string) (n int)
func main() {char := ""fmt.Println(utf8.RuneCountInString(char))// 1}注意: RuneCountInString 并不总是返回我们看到的字符数,因为有的字符会占用 2 个 rune:
func main() {char := "é"fmt.Println(len(char))// 3fmt.Println(utf8.RuneCountInString(char))// 2fmt.Println("cafe\u0301")// café// 法文的 cafe,实际上是两个 rune 的组合}21.在多行 array、slice、map 语句中缺少 , 号func main() {x := []int {1,2// syntax error: unexpected newline, expecting comma or }}y := []int{1,2,}z := []int{1,2}// ...}声明语句中 } 折叠到单行后,尾部的 , 不是必需的 。
22.log.Fatal 和 log.Panic 不只是 loglog 标准库提供了不同的日志记录等级,与其他语言的日志库不同,Go 的 log 包在调用 Fatal

推荐阅读