hello云胜

技术与生活

0%

深入理解Go的string

字符串类型是我们开发中最常用的类型。我们应该对Go语言的字符串有一个清晰完整的认识。

字符串

和java一样,go的string类型是不可变的。

go的优化点:

  • 对多行字符串的支持。

    在java里写多行字符串非常恶心,加一堆换行转义符。go只要用反引号引起来。你写什么就是什么。所见即所得。

  • 采用unicode编码,对中文支持友好。

字符串的长度问题

字符串的长度分字节长度和字符长度。一个汉字是一个字符,在unicode编码方案用utf-8编码存储的情况下,一个汉字是三个字节。

1
2
3
4
5
func TestChinese(t *testing.T) {
var s string = "中国"
t.Log("中国的字节长度是", len(s)) // 6
t.Log("中国的字符长度是", utf8.RuneCountInString(s)) // 2
}

直接len方法得到的时字节长度,utf8.RuneCountInString方法得到字符长度。

研究字符串之前,我们先研究下字符。

字符

rune这个看起来很陌生,似乎很难理解。但是其实只要类比java的char就好。

rune,在Go中,一个rune值表示一个Unicode码点。 我们可以将一个Unicode码点看作是一个Unicode字符,每个英文或中文Unicode字符只对应一个Unicode码点。

可以说,一个 rune 实例 就是一个 Unicode 字符,一个 Go的 字符串可以被视为 rune 实例的集合

unicode字符集

Unicode编码时一套字符集,也称万国码。从名字就可以感受到,unicode的目的是为了给世界上所有的字符设置其对应的编码,把所有的字符排成一队,某个字符在这个队伍中的位置点,就是上面说到的unicode码点。

比如汉字’中’的码点就是 4e2d。

一个rune字面量由若干包在一对单引号中的字符组成。包在单引号中的字符序列表示一个Unicode码点值。 rune字面量形式有几个变种,其中最常用的一种变种是将一个rune值对应的Unicode字符直接包在一对单引号中。比如:

1
2
'中' // 一个中文字符
'\u4e2d' // 使用\u或\U作前缀,表示一个Unicode字符

go中的字符使用unicode编码方案编码的,但是在存储上使用utf-8的方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func TestRune(t *testing.T) {
var c rune = '中'
t.Logf("中的unicode码点%x", c) // 4e2d

buf := make([]byte, 3)
utf8.EncodeRune(buf, c)
t.Logf("中的unicode码点的utf-8存储0x%x", buf) // 0xe4b8ad
// 一个汉字三个字节

// 对utf-8解码
r, size := utf8.DecodeRune(buf)
t.Logf("%s", string(r))
t.Log(size)
}