博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Strings、bytes and runes -- 就要学习Go语言
阅读量:2287 次
发布时间:2019-05-09

本文共 3272 字,大约阅读时间需要 10 分钟。

原创文章,若需转载请注明出处!

欢迎扫码关注公众号「Golang来了」或者移步 ,查看更多精彩文章。

Go 中的字符串值得特别关注,与其他语言相比,Go 中的字符串实现方式有所不同。

字符串

在Go中,使用双引号 "" 声明字符串:

s := "Hello world"fmt.Println("len(s):",len(s))fmt.Println(s);

输出:

len(s): 11Hello world

上面的代码声明了字符串 slen 函数返回字符串 s 的字节数(包括空格)。在 Go 中,字符串其实是只读的字节切片

s := "Hello world"for i:=0;i

你觉得上面的代码会输出什么,是一个个字母吗?其实不是:

72 101 108 108 111 32 119 111 114 108 100

输出的是每个字母在 上对应的十进制数字。

正如大家熟知的,Go 语言采用 UTF-8 编码,这种编码方式与 ASCII 编码兼容,只不过 ASCII 编码只需 1 个字节,而 UTF-8 需要 1-4 个字节表示一个符号。

s := "Hello world"for i:=0;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 格式化输出值的类型。从结果可以看出,值的类型都是 uint8byte 类型,typeuint8 的别名,byte 类型在我的中有所介绍。

我们来看下:一个字符串中包含非 ASCII 码的字符 会是怎样的情况。

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])}

len(s): 12H 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 ,其 占两个字节 c3b5for 循环按字节读取,c3 (十进制 195 )对应字符 Ãb5 (十进制 181 )对应字符 µ ()。
熟悉 ASCIIUTF-8Unicode 更有利于理解这些知识,关于这些知识,不会在本文展开细讲,有兴趣的可以参考。
UTF-8 编码中,一个码点占用至少一字节,如果我们还是以一个码点占用一个字节去打印字符肯定会出问题,就像上面的例子一样。那有没有办法解决这个问题,好在 Go 为我们提供了 rune

Rune

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): 11H 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 ,印证了 runeint32 的别名。

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。

文章读到这,可能会有个疑问,怎么获取字符串的长度呢?

Length of the string

可以使用 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]

这篇文章有几个比较重要的点:

  1. 字符串是只读的字节切片;
  2. rune 表示 Go 中的 Unicode 代码点;
  3. Go 采用 UTF-8 编码,这种编码方式是 Unicode 的实现方式之一;
  4. 熟悉 ASCIIUTF-8Unicode ,可以参考 ,更有利于理解这篇文章;

希望这篇文章能够解决你对 Go string 的一些疑问,有不懂的可以留言讨论!

(全文完)

扫描上方二维码,欢迎关注公众号「Golang来了」,获取最新精彩文章!

你可能感兴趣的文章
Spring Mvc整理
查看>>
Dubbo整理
查看>>
Redis整理
查看>>
JVM内存模型和类加载机制
查看>>
JDK1.0到12各版本新特性
查看>>
JAVA的一次编译,到处运行。可以在所有的平台上运行?
查看>>
HttpSessionListener监听器
查看>>
JSP
查看>>
Servlet九大内置对象
查看>>
JSTL
查看>>
el表达式
查看>>
日志 log4j的使用
查看>>
[Linux]虚拟机的安装、Linux的安装和Xshell的安装
查看>>
Linux的文件系统
查看>>
Linux的命令入门
查看>>
机器学习_算法_AdaBoost
查看>>
机器学习_算法_KNN
查看>>
Deep Learning_main
查看>>
Deep Learning_mnist background introduction
查看>>
linux_shell_util
查看>>