Go 中的字符串值得特别关注,与其余语言相比,Go 中的字符串实现方式有所不一样。html
在Go中,使用双引号 ""
声明字符串:golang
s := "Hello world"
fmt.Println("len(s):",len(s))
fmt.Println(s);
复制代码
输出:函数
len(s): 11
Hello world
复制代码
上面的代码声明了字符串 s
,len
函数返回字符串 s
的字节数(包括空格)。在 Go 中,字符串实际上是只读的字节切片。post
s := "Hello world"
for i:=0;i<len(s);i++ {
fmt.Print(s[i]," ")
}
复制代码
你以为上面的代码会输出什么,是一个个字母吗?其实不是:学习
72 101 108 108 111 32 119 111 114 108 100
复制代码
输出的是每一个字母在 ASCII 码表上对应的十进制数字。 正如你们熟知的,Go 语言采用 UTF-8
编码,这种编码方式与 ASCII
编码兼容,只不过 ASCII
编码只需 1 个字节,而 UTF-8
须要 1-4 个字节表示一个符号。ui
s := "Hello world"
for i:=0;i<len(s) ;i++ {
fmt.Printf("%c ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%v ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%x ",s[i])
}
fmt.Println("")
for i:=0;i<len(s) ;i++ {
fmt.Printf("%T ",s[i])
}
复制代码
输出:编码
H e l l o w o r l d
72 101 108 108 111 32 119 111 114 108 100
48 65 6c 6c 6f 20 77 6f 72 6c 64
uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8 uint8
复制代码
上面的代码,%v
格式化输出字节对应的十进制值;%x
以十六进制输出;%T
格式化输出值的类型。从结果能够看出,值的类型都是 uint8
即 byte
类型,byte
是 uint8
的别名,byte
类型在个人文章中有所介绍。 咱们来看下:一个字符串中包含非 ASCII
码的字符 会是怎样的状况。spa
s := "Hellõ World"
fmt.Println("len(s):", len(s))
for i := 0; i < len(s); i++ {
fmt.Printf("%c ", s[i])
}
fmt.Println("")
for i := 0; i < len(s); i++ {
fmt.Printf("%v ", s[i])
}
fmt.Println("")
for i := 0; i < len(s); i++ {
fmt.Printf("%x ", s[i])
}
复制代码
输出:.net
len(s): 12
H e l l à µ W o r l d
72 101 108 108 195 181 32 87 111 114 108 100
48 65 6c 6c c3 b5 20 57 6f 72 6c 64
复制代码
上面的例子中,将 o
替换成 õ
。从结果能够看出,字符串的字节长度是 12 ,说明 õ
占用两个字节。然而 õ
的输出变成了 Ã µ
, õ
的 Unicode
码点是 U+00F5
,其 UTF-8 编码 占两个字节 c3
、b5
。for
循环按字节读取,c3
(十进制 195 )对应字符 Ã
, b5
(十进制 181 )对应字符 µ
(详见这里)。 熟悉 ASCII
、UTF-8
和 Unicode
更有利于理解这些知识,关于这些知识,不会在本文展开细讲,有兴趣的能够参考这里。 UTF-8
编码中,一个码点占用至少一字节,若是咱们仍是以一个码点占用一个字节去打印字符确定会出问题,就像上面的例子同样。那有没有办法解决这个问题,好在 Go 为咱们提供了 rune
。code
rune
是 Go 的内置数据类型,是 int32
的别名,表示 Go 中的 Unicode
代码点。用 rune
数据类型,开发人员就没必要关心代码点占用几个字节了。
s := "Hellõ World"
r := []rune(s)
fmt.Println("len(r):", len(r))
for i := 0; i < len(r); i++ {
fmt.Printf("%c ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%v ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%x ", r[i])
}
fmt.Println("")
for i := 0; i < len(r); i++ {
fmt.Printf("%T ", r[i])
}
复制代码
输出:
len(r): 11
H e l l õ W o r l d
72 101 108 108 245 32 87 111 114 108 100
48 65 6c 6c f5 20 57 6f 72 6c 64
int32 int32 int32 int32 int32 int32 int32 int32 int32 int32 int32
复制代码
上面的代码,字符串 s
经过类型转化成了 rune
切片。 õ
的 Unicode
码点就是 U+00F5
,对应十进制的 245 ,参考这。切片 r
的长度就是:11 ;输出的 int32
,印证了 rune
是 int32
的别名。
for range
字符串上面的例子已经很好解决了以前遇到的问题,有种更好的方式 -- range string
。使用 range
循环一个字符串,将返回 rune
类型的字符和字节索引。
s := "HellõWorld"
for index, char := range s {
fmt.Printf("%c starts at byte index %d \n", char,index)
}
复制代码
输出:
H starts at byte index 0
e starts at byte index 1
l starts at byte index 2
l starts at byte index 3
õ starts at byte index 4
W starts at byte index 6
o starts at byte index 7
r starts at byte index 8
l starts at byte index 9
d starts at byte index 10
复制代码
从输出结果能够看出,õ
占用了两个字节:索引 4 和 5。
文章读到这,可能会有个疑问,怎么获取字符串的长度呢?
可使用 RuneCountInString()
函数,原型是这样的:
func RuneCountInString(s string) (n int) 复制代码
返回字符串中 rune
字符的个数。
s := "Hellõ 中国"
length := utf8.RuneCountInString(s)
fmt.Println(length)
复制代码
输出:8
前面咱们已经说过,字符串是只读的字节切片,一旦建立,是不可更改的。若是强制修改,就会报错:
s := "Hello World"
s[0] = "h"
复制代码
报错:cannot assign to s[0]
这篇文章有几点比较重要:
rune
表示 Go 中的 Unicode
代码点;UTF-8
编码,这种编码方式是 Unicode
的实现方式之一;ASCII
、UTF-8
和 Unicode
,能够参考 这,更有利于理解这篇文章;但愿这篇文章可以解决你对 Go string
的一些疑问,有不懂的能够留言讨论!
原创文章,若需转载请注明出处!
欢迎扫码关注公众号「Golang来啦」或者移步 seekload.net ,查看更多精彩文章。
公众号「Golang来啦」给你准备了一份神秘学习大礼包,后台回复【电子书】领取!