星星博客 »  > 

Go 字符串——遍历及切片

一、遍历

go的遍历有以下两种方式,但是直接打印输出的为数字,与我们想要的结果不同。这是因为在Go里,字符串存储的是类型为byte的字节切片,而byte实际为uint8类型的值,即存储一个字符串时,存储的不是字符,而是字符对应的字节。那为什么两种遍历输出的数值不一样呢,接着往下看。

func main() {
	str := "hello, 世界"

    fmt.Println("test 1-------")
	for i := 0; i < len(str); i++ {
		fmt.Println(str[i])
	}

    fmt.Println("test 2-------")
	for _, i := range str {
		fmt.Println(i)
	}
}

// 输出
test 1-------
104
101
108
108
111
44
32
228
184
150
231
149
140
test 2-------
104
101
108
108
111
44
32
19990
30028

正确的遍历姿势,可以看到第二种方式能够正确遍历字符串了,但是第一种方式的中文输出了一堆字符。这是因为第一种方式为utf-8遍历,第二种为Unicode遍历。utf-8为一种可变字节编码,长度有1-4个字节,上面例子中的中文就是三个字节,因此强转为string类型打印时,一个中文打印了三个字节对应的字符。Unicode是一个字符集,每个字符(包括中英文及特殊字符等)都有对应的唯一码点,range遍历时会将字节解码为rune类型,该类型能表示一个Unicode字符,因此强转后能正确打印。

func main() {
	str := "hello, 世界"

	fmt.Println("test 1-------")
	for i := 0; i < len(str); i++ {
		fmt.Println(string(str[i]))
	}

	fmt.Println("test 2-------")
	for _, i := range str {
		fmt.Println(string(i))
	}
}


// 输出
test 1-------
h
e
l
l
o
,

ä
¸

ç


test 2-------
h
e
l
l
o
,

世
界

二、切片

例子中,本想截取前三个字符,但是第一种方式只打印出一个字符,理由和上面说的一样,字符串底层存储的是字节,刚好例子中中文为三个字节,因此把第一个中文打印出来。第二种方式将字符串转为rune类型数组,存储的是Unicode码点,因此将截取的字符强转后能正确打印

func main() {
	str := "截取切片"
	fmt.Println("test 1")
	fmt.Println(str[:3])

    fmt.Println("test 2")
	str2 := []rune(str)
	fmt.Println(string(str2[:3]))
}


// 输出
test 1
截
test 2
截取切

 

相关文章