28

4. Go语言中byte、rune与字符串区别?

 4 years ago
source link: https://studygolang.com/articles/27592
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

文章首发自公众号:Go编程时光

《Go编程时光》,一个能带你学习 Go 语言的专栏,同时欢迎搜索我的同名公众号【Go编程时光】(排版精美更适合阅读),第一时间获取Go语言干货。

系列导读

1. 一文搞定Go语言开发环境的搭建

2. Go 语言中五种变量创建的方法

3. Go语言中的整型与浮点型

1. byte 与 rune

byte,占用1个节字,就 8 个比特位,所以它和 uint8 类型本质上没有区别,它表示的是 ACSII 表中的一个字符。

如下这段代码,分别定义了 byte 类型和 uint8 类型的变量 a 和 b

import "fmt"

func main() {
    var a byte = 65 
    // 8进制写法: var c byte = '\101'     其中 \ 是固定前缀
    // 16进制写法: var c byte = '\x41'    其中 \x 是固定前缀
    
	var b uint8 = 66
    fmt.Printf("a 的值: %c \nb 的值: %c", a, b)
    // 或者使用 string 函数
    // fmt.Println("a 的值: ", string(a)," \nb 的值: ", string(b))
}
复制代码

在 ASCII 表中,由于字母 A 的ASCII 的编号为 65 ,字母 B 的ASCII 编号为 66,所以上面的代码也可以写成这样

import "fmt"

func main() {
	var a byte = 'A'
	var b uint8 = 'B'
    fmt.Printf("a 的值: %c \nb 的值: %c", a, b)
}
复制代码

他们的输出结果都是一样的。

a 的值: A 
b 的值: B
复制代码

rune,占用4个字节,共32位比特位,所以它和 uint32 本质上也没有区别。它表示的是一个 Unicode字符(Unicode是一个可以表示世界范围内的绝大部分字符的编码规范)。

import (
	"fmt"
	"unsafe"
)

func main() {
	var a byte = 'A'
	var b rune = 'B'
	fmt.Printf("a 占用 %d 个字节数\nb 占用 %d 个字节数", unsafe.Sizeof(a), unsafe.Sizeof(b))
}
复制代码

输出如下

a 占用 1 个字节数
b 占用 4 个字节数
复制代码

由于 byte 类型能表示的值是有限,只有 2^8=256 个。所以如果你想表示中文的话,你只能使用 rune 类型。

var name rune = '中'
复制代码

或许你已经发现,上面我们在定义字符时,不管是 byte 还是 rune ,我都是使用单引号,而没使用双引号。

对于从 Python 转过来的人,这里一定要注意了,在 Go 中单引号与 双引号并不是等价的。

单引号用来表示字符,在上面的例子里,如果你使用双引号,就意味着你要定义一个字符串,赋值时与前面声明的前面会不一致,这样在编译的时候就会出错。

cannot use "A" (type string) as type byte in assignment
复制代码

上面我说了,byte 和 uint8 没有区别,rune 和 uint32 没有区别,那为什么还要多出一个 byte 和 rune 类型呢?

理由很简单,因为uint8 和 uint32 ,直观上让人以为这是一个数值,但是实际上,它也可以表示一个字符,所以为了消除这种直观错觉,就诞生了 byte 和 rune 这两个别名类型。

2. 字符串

字符串,可以说是大家很熟悉的数据类型之一。定义方法很简单

var mystr string = "hello"
复制代码

上面说的byte 和 rune 都是字符类型,若多个字符放在一起,就组成了字符串,也就是这里要说的 string 类型。

比如 hello ,对照 ascii 编码表,每个字母对应的编号是:104,101,108,108,111

import (
	"fmt"
)

func main() {
    var mystr01 sting = "hello"
	var mystr02 [5]byte = [5]byte{104, 101, 108, 108, 111}
    fmt.Printf("mystr01: %s\n", mystr01)
	fmt.Printf("mystr02: %s", mystr02)
}
复制代码

输出如下,mystr01 和 mystr02 输出一样,说明了 string 的本质,其实是一个 byte数组

mystr01: hello
mystr02: hello
复制代码

通过以上学习,我们知道字符分为 byte 和 rune,占用的大小不同。

这里来考一下大家, hello,中国 占用几个字节?

要回答这个问题,你得知道 Go 语言的 string 是用 uft-8 进行编码的,英文字母占用一个字节,而中文字母占用 3个字节,所以 hello,中国 的长度为 5+1+(3*2)= 12个字节。

import (
	"fmt"
)

func main() {
	var country string = "hello,中国"
	fmt.Println(len(country))
}
// 输出
12
复制代码

以上虽然我都用双引号表示 一个字符串,但这并不是字符串的唯一表示方式。

除了双引号之外 ,你还可以使用反引号。

大多情况下,二者并没有区别,但如果你的字符串中有转义字符 \ ,这里就要注意了,它们是有区别的。

使用反引号号包裹的字符串,相当于 Python 中的 raw 字符串,会忽略里面的转义。

比如我想表示 \r\n 这个 字符串,使用双引号是这样写的,这种叫解释型表示法

var mystr01 string = "\\r\\n"
复制代码

而使用反引号,就方便多了,所见即所得,这种叫原生型表示法

var mystr02 string = `\r\n`
复制代码

他们的打印结果 都是一样的

import (
	"fmt"
)

func main() {
	var mystr01 string = "\\r\\n"
	var mystr02 string = `\r\n`
	fmt.Println(mystr01)
	fmt.Println(mystr02)
}

// output
\r\n
\r\n
复制代码

如果你仍然想使用解释型的字符串,但是各种转义实在太麻烦了。你可以使用 fmt 的 %q 来还原一下。

import (
	"fmt"
)

func main() {
	var mystr01 string = `\r\n`
	fmt.Println(`\r\n`)
	fmt.Printf("的解释型字符串是: %q", mystr01)
}
复制代码

输出如下

\r\n
的解释型字符串是: "\\r\\n"
复制代码

同时反引号可以不写换行符(因为没法写)来表示一个多行的字符串。

import (
	"fmt"
)

func main() {
	var mystr01 string = `你好呀!
我的公众号是: Go编程时光,欢迎大家关注`

	fmt.Println(mystr01)
}
复制代码

输出如下

你好呀!
我的公众号是: Go编程时光,欢迎大家关注
复制代码
nIziIbE.png!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK