Go语言学习
  • README
  • Go 基础
    • go语言介绍
    • go语言主要特性
    • go内置类型和函数
    • init函数和main函数
    • 下划线
    • iota
    • 字符串
    • 数据类型:数组与切片
    • 数据类型:byte、rune与字符串
    • 变量的5种创建方式
    • 数据类型:字典
    • 指针
    • 数据类型:指针
    • 类型断言
    • 流程控制:defer延迟执行
    • 异常机制:panic和recover
    • 函数
    • go依赖管理
    • go中值传递、引用传递、指针传递区别
  • 标准库
    • Go net/http包
  • 数据结构
    • 哈希表
      • 为什么对 map 的 key 或 value 进行取址操作是不允许的
  • Gin
    • gin 快速开始
    • gin-swagger用法
  • Go 进阶
    • Go 指针
    • Go 中的 GC 演变是怎样的?
    • Go 的堆和栈
  • 面向对象
    • make 和 new 的区别
    • new(T) 和 &T{} 有什么区别?
  • 并发编程
    • Channel
    • Go语言 CSP 并发模型
    • GMP 模型原理
      • GMP 模型为什么要有 P ?
    • Go 协程池(goroutine pool)
    • Go语言常见的并发模式
    • Go并发实践:主动停止goroutine
  • 最佳实践
    • 发布Go语言模块
  • 软件包
    • 常用的GoLang包工具
    • Go的UUID生成
    • 现代化的命令行框架Cobra
    • 配置解析神器Viper
    • Go发送邮件gomail
    • Go反射框架Fx
    • NSQ消息队列的使用
    • Go爬虫框架colly
    • grpc-go 的安装和使用
Powered by GitBook
On this page
  • byte 与 rune[]
  • 字符串

Was this helpful?

  1. Go 基础

数据类型:byte、rune与字符串

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 ,我都是使用单引号,而没使用双引号。

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

cannot use "A" (type string) as type byte in assignment

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

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

字符串

定义方法很简单

var str string = "hello world"

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

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

import (
    "fmt"
)

func main() {
    var mystr01 string = "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这个 字符串,使用双引号是这样写的,这种叫解释型表示法

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 = `你好呀!
张三
`

    fmt.Println(mystr01)
}

输出如下

你好呀!
张三
Previous数据类型:数组与切片Next变量的5种创建方式

Last updated 2 years ago

Was this helpful?