rune类型
Go语言的字符有以下两种:
一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。
另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型等价于 int32 类型。
byte 类型是 uint8 的别名,对于只占用 1 个字节的传统 ASCII 编码的字符来说,完全没有问题,例如 var ch byte = 'A',字符使用单引号括起来。
Go语言同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,并在内存中使用 int 来表示。在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数。
在书写 Unicode 字符时,需要在 16 进制数之前加上前缀\u或者\U。因为 Unicode 至少占用 2 个字节,所以我们使用 int16 或者 int 类型来表示。如果需要使用到 4 字节,则使用\u前缀,如果需要使用到 8 个字节,则使用\U前缀。
Unicode 包中内置了一些用于测试字符的函数,这些函数的返回值都是一个布尔值,如下所示(其中 ch 代表字符):
判断是否为字母:unicode.IsLetter(ch)
判断是否为数字:unicode.IsDigit(ch)
判断是否为空白符号:unicode.IsSpace(ch)
双引号和单引号
单引号
v := 'n' // 修改这里!
fmt.Printf("v is of type %T\n", v) //v is of type int32
输出单引号的变量,发现其类型是int32。
go语言使用一个特殊类型 rune 表示字符型。rune 为 int32 的别名,它完全等价于 int32,习惯上用它来区别字符值和整数值。rune 表示字符的 Unicode 码值。
双引号
Go中,双引号是用来表示字符串string,其实质是一个byte类型的数组。
Go中字符串是一个不可变的值类型,内部用指针指向UTF-8字节数组。因此可以用索引号访问某字节,也可以用len()函数来获取字符串所占的字节长度。例如:
s := "hello 世界"
fmt.Println(s[0]) //104
fmt.Println(len(s)) //12
fmt.Println(s) //hello 世界
fmt.Println(reflect.TypeOf(s[0]))//uint8
fmt.Println(string(s[0])) //h
第一个语句会打印数字而不是字符。这是由于go语言中的字符串实际上是类型为byte的只读切片。或者说一个字符串就是一堆字节。这意味着,当我们将字符存储在字符串中时,实际存储的是这个字符的字节。一个字符串包含了任意个byte,它并不限定Unicode,UTF-8或者任何其他预定义的编码。因为遍历字符串有时候可以是utf-8的编码(下面会讲到)。
在这里s[0]类型为uint8,也就是byte类型。
len(s)结果为12,因为golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8。
因此 len(s)=6+2*3=12
,len(s)获取的是底层字节码长度
那么?如果我们预期想得到一个字符串的长度,而不是字符串底层占得字节长度,该怎么办呢???
- 引入"unicode/utf8"包
//golang中的unicode/utf8包提供了用utf-8获取长度的方法
fmt.Println("RuneCountInString:", utf8.RuneCountInString(s))
- 通过rune类型处理unicode字符,类型强转
//通过rune类型处理unicode字符
fmt.Println("rune:", len([]rune(s)))
反引号
反引号用来创建原生的字符串字面量 ,这些字符串可能由多行组成,不支持任何转义序列。原生的字符串字面量多用于书写多行消息、HTML 以及正则表达式。
str := `hello\n世界
我是 abboo`
fmt.Println(str)
/*
hello\n世界
我是 abboo
*/
会将字符串的全部输出,你看到是什么就是什么
强类型
go是强类型语言,因此,当把两个不同类型的变量进行拼接时,就会报错。
字符串拼接
有时使用 fmt.Printf() 输出时,由于格式化字符串太长,想分多行书写,但是又不想引入换行。此时就可以将多行的字符串使用运算符 + 拼接在一起。
字符串拼接符+。在实际使用时还需要注意,当拼接的字符串位于不同行时,拼接符需要放在上一行的末尾,这是因为编译器会进行行尾自动补全分号的缘故。例如:
str:="hello"+
"world"
或者使用Go标准包也提供的函数strings.Join()来实现这一功能。
str1:=[]string{"hello","world"}
str:=strings.Join(str1,",")
fmt.Println(str)
字符串遍历
go中有两种方式对字符串进行遍历,一种是utf-8遍历,另一种是Unicode遍历。
//utf-8遍历
for i := 0; i < len(s); i++ {
ch1 := s[i]
ctype:=reflect.TypeOf(ch1)
fmt.Printf("%s ",ctype) //uint8
}
fmt.Println("=============>Unicode遍历")
//Unicode遍历
for _, ch1 := range s {
ctype:=reflect.TypeOf(ch1)
fmt.Printf("%s ",ctype) //int32
}
当然这种遍历都会打印一堆数字
代码运行后显示ch1的类型为uint8,也就是byte类型,而ch1的类型为int32,也就是rune类型。
go语言中的源码定义为utf-8文本,不允许其他的表示。但是也存在特殊处理,那就是字符串上使用for…range循环。range循环迭代时,就会解码一个utf-8编码的rune。
现在既然已经知道上述不管哪种遍历方式,其实质都是字节。所以在打印时,只需要将这些结果转化为字符字面值或者转换其输出类型就可以了。
//方法一:格式化打印
for _, ch1 := range s {
fmt.Printf("%q",ch1) //单引号围绕的字符字面值,由go语法安全的转义
}
fmt.Println("==========>方法二")
//方法二:转化输出格式
for _, ch2 := range s{
fmt.Println(string(ch2))
}
有疑问加站长微信联系(非本文作者)