Go byte、rune和string,你真的用明白了吗

1,946 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5天,点击查看活动详情

byte

一般用于强调数值是原始数据,代表ASCII码的一个字符(占一个字节)。等价于uint8

//使用单引号 表示一个字符
var ch byte = 'A'
//在 ASCII 码表中,A 的值是 65,也可以这么定义
var ch byte = 65
//65使用十六进制表示是41,所以也可以这么定义 \x 总是紧跟着长度为 2 的 16 进制数
var ch byte = '\x41'
//65的八进制表示是101,所以使用八进制定义 \后面紧跟着长度为 3 的八进制数
var ch byte = '\101'

fmt.Printf("%c",ch)

rune

用于标识Unicode字符,代表一个UTF-8字符。等价于int32

var ch rune = '\u0041'
var ch1 int64 = '\U00000041'
//格式化说明符%c用于表示字符,%v或%d会输出用于表示该字符的整数,%U输出格式为 U+hhhh 的字符串。
fmt.Printf("%c,%c,%U",ch,ch1,ch)

string

多行字符串

反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出

s1 := `第一行
第二行
第三行
`
fmt.Println(s1)

获取字符串长度

ASCII字符使用len()函数

Unicode字符串长度使用utf8.RuneCountInString()函数

字符串拼接

方式1:使用+

var s string
s += "你好,世界"
fmt.Println(s)
//输出:你好,世界

方式2:使用WriterString()

var sb bytes.Buffer
sb.WriteString("你好,")
sb.WriteString("世界")
fmt.Println(sb.String())
//输出:你好,世界

使用索引获取字符

var myStr01 string = "hello,北京"

fmt.Println(string([]rune(myStr01)[1]))
fmt.Println(string([]rune(myStr01)[6]))
fmt.Println(string(myStr01[6]))   //中文会乱码,用上一行的方法处理
//输出:e 
//     北
//     ç

遍历字符串

使用forfor range,但效果有所差异。

for按byte处理,有中文会乱码;for range按rune处理,有中文不会乱码

func traversalString() {
  s := "hello沙河"
  for i := 0; i < len(s); i++ { //byte
    fmt.Printf("%v(%c) ", s[i], s[i])
  }
  fmt.Println()
  
  for _, r := range s { //rune
    fmt.Printf("%v(%c) ", r, r)
  }
  fmt.Println()
}

//输出:
//104(h) 101(e) 108(l) 108(l) 111(o) 230(æ) 178(²) 153() 230(æ) 178(²) 179(³) 
//104(h) 101(e) 108(l) 108(l) 111(o) 27801(沙) 27827(河) 

//说明:因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果

修改字符串

直接通过下标修改字符串是不允许的。字符串底层是一个byte数组,所以可以和[]byte类型相互转换

要修改字符串,需要先将其转换成[]rune[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组。

func changeString() {
  s1 := "big"
  // 强制类型转换
  byteS1 := []byte(s1)
  byteS1[0] = 'p'
  fmt.Println(string(byteS1))

  s2 := "白萝卜"
  runeS2 := []rune(s2)
  runeS2[0] = '红'
  fmt.Println(string(runeS2))
}

如果本文对你有帮助,欢迎点赞收藏加关注,如果本文有错误的地方,欢迎指出!