我们知道Golang字符串可以用操作[]byte相同的方式来操作,可以用下标来访问,也可以取子串,用下标来访问的话,每个元素的类型是个byte(uint8),例如

func SubStr(s string, start, length int) string {
	return s[start:start+length]
}

func main() {
	str := "abcde12345"
	char := str[3]
	fmt.Println(char, reflect.ValueOf(char).Kind()) // 100 uint8
	sub := str[3:7]
	fmt.Println(sub) // de12
	fmt.Println(SubStr("hello world!", 6, 5)) // world
	str2 := "你好,China"
	for i := 0; i < len(str2); i++ {
		fmt.Println(i, str2[i], reflect.ValueOf(str2[i]).Kind())
		/*		
		0 228 uint8
		1 189 uint8
		2 160 uint8
		3 229 uint8
		4 165 uint8
		5 189 uint8
		6 239 uint8
		7 188 uint8
		8 140 uint8
		9 67 uint8
		10 104 uint8
		11 105 uint8
		12 110 uint8
		13 97 uint8
		*/
	}
}

从上面可以看出,Golang的字符串操作和把字符串转成[]byte之后的操作基本一致,除了取子串时一个返回的是字符串,一个返回的是另一个[]byte,但注意如果用for…range来遍历一个字符串,表现则完全不同,这也是我们平时使用时需要注意的一点,例如:

func main() {
	str := "你好,China"
	for i, char := range str {
		fmt.Println(i, char, reflect.ValueOf(char).Kind())
		// 0 20320 int32
		// 3 22909 int32
		// 6 65292 int32
		// 9 67 int32
		// 10 104 int32
		// 11 105 int32
		// 12 110 int32
		// 13 97 int32
	}
}

for…range遍历字符串每个元素的类型是rune(int32),即utf-8字符对应的unicode码点,而索引是每个utf-8字符的第一个字节在字符串中的下标,对比下把字符串转换为[]rune的区别

func main() {
	str := "你好,China"
	unicodes := []rune(str)
	for i, char := range unicodes {
		fmt.Println(i, char, reflect.ValueOf(char).Kind())
		// 0 20320 int32
		// 1 22909 int32
		// 2 65292 int32
		// 3 67 int32
		// 4 104 int32
		// 5 105 int32
		// 6 110 int32
		// 7 97 int32
	}
}

遍历出来的索引和for…range不同,所以平时的使用应特别注意用for…range来遍历一个字符串的奇怪表现,避免用错。