go语言打怪通关之 ⌈常量、变量、数据结构⌋
我是一名来自帝都985高校的机械研究生
本号专注于分享工科专业学习考试攻略、程序员学习求职经验、教师求职考试经验等相关内容,同时还会兼顾生活向,欢迎大家的关注和转发!
目录
常量
变量
多重赋值
数据结构
整型
浮点型
布尔类型
字符串
格式化字符串
字符类型
数组
切片
包
常量
常量使用关键字 const
声明,下面有几个例子:
const limit = 512
const top uint16 = 1421
const Pi float64 = 3.1415926
const x,y int = 1,3 //多重赋值
Go 的常量定义可以限定常量类型,但不是必需的。如果定义常量时没有指定类型,那么该常量就是无类型常量
,也叫字面常量
。
当需要设置多个常量的时候,不必重复使用 const
关键字,可以使用以下语法:
const (
Cyan = 0
Black = 1
White = 2
)
Go 语言还预定义了这些常量:true
、false
、iota
。
iota
是一个可以被编译器修改的常量,「在 const
关键字出现时被重置为 0,在下一个 const 出现之前,每出现一次 iota,其所代表的数字自动加 1」。下面通过一个例子讲解 iota 的用法:
const (
a = iota //a == 0
b = iota //b ==1
c = iota //c == 2
)
const d = iota //d==0,因为const的出现,iota被重置为0
变量
变量是所有语言最基本和最重要的组成部分。Go 语言引入了关键字 var
对变量进行声明,也可以使用 :=
来对变量直接进行初始化,Go 编译器会自动推导出该变量的类型,这大大的方便了开发者的工作。「需要注意的是 :=
左侧的变量不能是已经被声明过的,否则会导致编译器错误」。
以下是 Go 声明和初始化变量的各种方法:
var a int
var b string
var c float64
var d [5] int //数组
var e [] int //数组切片
var f * int //正确
var v1 int = 5 //正确
var v2 = 5 //正确,编译器自动推导出V2类型
v3 := 5 //正确,编译器自动推导出V3的类型
多重赋值
Go 语言提供了大多数语言不支持的多重赋值,这使得变量的交换变得十分简单。下面通过一个例子来了解 Go 语言的多重赋值:
i := 2
j := 3
i, j = j, i //交换i和j的值,此时i == 3,j == 2
这样的方式可以一行代码实现变量的交换,明显的减少代码的行数,而不需要像 C/C++ 那样引入一个中间变量。
数据结构
整型
Go 语言提供了 11 种整型,如下列表所示。
类型 | 说明 |
---|---|
byte | 等同于 uint8 |
int | 依赖于不同平台下的实现,可以是 int32 或者 int64 |
int8 | [-128, 127] |
int16 | [-32768, 32767] |
int32 | [-2147483648, 2147483647] |
int64 | [-9223372036854775808, 9223372036854775807] |
rune | 等同于 int32 |
uint | 依赖于不同平台下的实现,可以是 uint32 或者 uint64 |
uint8 | [0, 255] |
uint16 | [0, 65535] |
uint32 | [0, 4294967295] |
uint64 | [0, 18446744073709551615] |
uintptr | 一个可以恰好容纳指针值的无符号整型(对 32 位平台是 uint32, 对 64 位平台是 uint64) |
在 C
语言中我们可以通过 sizeof
操作符查看类型的字节长度,在 Go
语言中可以通过 unsafe.Sizeof
函数进行。
浮点型
Go 语言提供了两种浮点类型和两种复数类型,具体如下:
类型 | 说明 |
---|---|
float32 | ±3.402 823 466 385 288 598 117 041 834 845 169 254 40x1038 计算精度大概是小数点后 7 个十进制数 |
float64 | ±1.797 693 134 862 315 708 145 274 237 317 043 567 981x1038 计算精度大概是小数点后 15 个十进制数 |
complex32 | 复数,实部和虚部都是 float32 |
complex64 | 复数,实部和虚部都是 float64 |
布尔类型
Go 语言提供了内置的布尔值 true
和false
。Go 语言支持标准的逻辑和比较操作,这些操作的结果都是布尔值。值得注意的地方是可以通过 !b
的方式反转变量 b
的真假。需要注意的是布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。实例代码如下:
var a bool
a = true
b := (2 == 3) //b也会被推导为bool类型
//错误示范
var b bool
b = 1 //编译错误
b = bool(1) //编译错误
字符串
Go 语言中的字符串是 UTF-8 字符的一个序列(当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节)。UTF-8 是被广泛使用的编码格式,是文本文件的标准编码,其它包括 XML 和 JSON 在内,也都使用该编码。
由于该编码对占用字节长度的不定性,Go 中的字符串也可能根据需要占用 1 至 4 个字节,这与其它语言如 C++、Java 或者 Python 不同。「Go 这样做的好处是不仅减少了内存和硬盘空间占用,同时也不用像其它语言那样需要对使用 UTF-8 字符集的文本进行编码和解码。」
Go 语言中字符串的可以使用双引号 (")
或者反引号 (`) 来创建。
「双引号」用来创建可解析的字符串字面量,所谓可解析的是指字符串中的一些符号可以被格式化为其他内容,如 \n 在在输出时候会被格式化成换行符,如果需要按照原始字符输出必须进行转义。
而「反引号」创建的字符串原始是什么样,那输出还是什么,不需要进行任何转义。以下是几个例子:
t1 := "\"hello\"" //内容: "hello"
t2 := `"hello"` //内容:和t1一致
t3 := "\u6B22\u8FCE" //内容:欢迎
Go 语言中的部分转义字符如下表所示:
转义字符 | 含义 |
---|---|
\\ |
表示反斜线 |
\' |
单引号 |
\" |
双引号 |
\n |
换行符 |
\uhhhh |
4 个 16 进制数字给定的 Unicode 字符 |
在 Go 语言中单个字符可以使用单引号 (') 来创建。在 Go 语言中,一个单一的字符可以用一个单一的 rune 来表示。这也是容易理解的,因为 Go 语言的字符串是 UTF-8 编码,其底层使用 4 个字节表示,也就是 32 bit。
在 Go 语言中,字符串支持「切片操作」,但是需要注意的是如果字符串都是由 ASCII 字符组成,那可以随便使用切片进行操作,但是如果字符串中包含其他非 ASCII 字符,直接使用切片获取想要的单个字符时需要十分小心,因为对字符串直接使用切片时是通过字节进行索引的,但是非 ASCII 字符在内存中可能不是由一个字节组成。
如果想对字符串中字符依次访问,可以使用 range
操作符。另外获取字符串的长度可能有两种含义,一种是指获取字符串的字节长度,一种是指获取字符串的字符数量。字符串支持以下操作:
语法 | 描述 |
---|---|
s += t | 将字符串 t 追加到 s 末尾 |
s + t | 将字符串 s 和 t 级联 |
s[n] | 从字符串 s 中索引位置为 n 处的原始字节 |
s[n:m] | 从位置 n 到位置 m-1 处取得的字符(字节)串 |
s[n:] | 从位置 n 到位置 len(s)-1 处取得的字符(字节)串 |
s[:m] | 从位置 0 到位置 m-1 处取得的字符(字节)串 |
len(s) | 字符串 s 中的字节数 |
len([]rune(s)) | 字符串 s 中字符的个数,可以使用更快的方法 utf8.RuneCountInString() |
[]rune(s) | 将字符串 s 转换为一个 unicode 值组成的串 |
string(chars) | chars 类型是 []rune 或者 []int32, 将之转换为字符串 |
[]byte(s) | 无副本的将字符串 s 转换为一个原始的字节的切片数组,不保证转换的字节是合法的 UTF-8 编码字节 |
格式化字符串
Go 语言标准库中的 fmt
包提供了打印函数将数据以字符串形式输出到控制台、文件、其他满足 io.Writer 接口的值以及其他字符串。目前为止我们使用了 fmt.Printf
和 fmt.Println
,对于前者的使用,就像 C 语言中的 printf
函数一样,我们可以提供一些格式化指令,让 Go 语言对输出的字符串进行格式化。同样的我们可以使用一些格式化修饰符,改变格式化指令的输出结果, 如左对齐等。常用的格式化指令如下:
格式化指令 | 含义 |
---|---|
%% | % 字面量 |
%b | 一个二进制整数,将一个整数格式化为二进制的表达方式 |
%c | 一个 Unicode 的字符 |
%d | 十进制数值 |
%o | 八进制数值 |
%x | 小写的十六进制数值 |
%X | 大写的十六进制数值 |
%U | 一个 Unicode 表示法表示的整形码值,默认是 4 个数字字符 |
%s | 输出以原生的 UTF-8 字节表示的字符,如果 console 不支持 UTF-8 编码,则会输出乱码 |
%t | 以 true 或者 false 的方式输出布尔值 |
%v | 使用默认格式输出值,或者使用类型的 String() 方法输出的自定义值,如果该方法存在的话 |
%T | 输出值的类型 |
常用的格式化指令修饰符如下:
-
空白
如果输出的数字为负,则在其前面加上一个减号 -。如果输出的是整数,则在前面加一个空格。使用%x
或者%X
格式化指令输出时,会在结果之间添加一个空格。例如fmt.Printf("% X", "实")
输出 E5 AE 9E。 -
#
-
%#o
输出以0
开始的八进制数据。 -
%#x
输出以0x
开始的十六进制数据。 -
+
让格式化指令在数值前面输出 + 号或者 - 号,为字符串输出 ASCII 字符(非 ASCII 字符会被转义),为结构体输出其字段名。 -
-
让格式化指令将值向左对齐(默认值为像右对齐)。 -
0
让格式指令以数字 0 而非空白进行填充。
字符类型
在 Go 语言中支持两个字符类型,一个是 Byte
(实际上是 Unit8 的别名),代表 UTF-8 字符串的单个字节的值;另一个是 rune
,代表单个 Unicode 字符。
处于简化语言的考虑,Go 语言的多数 API 都假设字符串为 UTF-8 编码。尽管 Unicode 字符在标准库中有支持,但实际很少使用。
数组
Go 语言的数组是一个定长的序列,其中的元素类型相同。多维数组可以简单地使用自身为数组的元素来创建。数组的元素使用操作符号 [ ] 来索引,索引从 0 开始,到 len(array)-1 结束。数组使用以下语法创建:
[length]Type
[N]Type{value1, value2, ..., valueN}
[...]Type{value1, value2, ..., valueN}
如果使用了 ...(省略符)操作符,Go 语言会为我们自动计算数组的长度。在任何情况下,一个数组的长度都是固定的并且不可修改。数组的长度可以使用 len()
函数获得。
由于数组的长度是固定的,因此数组的长度和容量都是一样的,因此对于数组而言 cap()
和 len()
函数返回值都是一样的。数组也可以使用和切片一样的语法进行切片,只是其结果为一个切片,而非数组。同样的,数组也可以使用 range
进行索引访问。
切片
一般而言,Go 语言的切片比数组更加灵活,强大而且方便。「数组是按值传递的(即是传递的副本),而切片是引用类型」,传递切片的成本非常小,而且是不定长的。而且数组是定长的,而切片可以调整长度。创建切片的语法如下:
make([ ]Type, length, capacity)
make([ ]Type, length)
[ ]Type{}
[ ]Type{value1, value2, ..., valueN}
内置函数 make()
用于创建切片、映射和通道。当用于创建一个切片时,它会创建一个隐藏的初始化为零值的数组,然后返回一个引用该隐藏数组的切片。该隐藏的数组与 Go 语言中的所有数组一样,都是固定长度。
如果使用第一种语法创建,那么其长度为切片的容量 capacity
;如果是第二种语法,那么其长度记为切片的长度 length
。一个切片的容量即为隐藏数组的长度,而其长度则为不超过该容量的任意值。另外可以通过内置的函数 append()
来增加切片的容量。
包
这一节我们介绍 Go 语言基础的最后一个知识点——包。前面我们了解过 Go 语言组织代码的方式是包,包是各种类型和函数的集合。在包中,如果标示符(类型名称,函数名称,方法名称)的首字母是大写,那这些标示符是可以被导出的,也就是说可以在包以外直接使用。前面我们也提到了 GOPATH和
GOROOT` 目录中搜索包。
我们创建的自定义的包最好放在 GOPATH 的 src 目录下,每个包单独放在一个目录里,如果两个不同的包放在同一目录下,会出现名字冲突的编译错误。作为惯例,包的源代码应该放在一个同名的文件夹下面。同一个包可以有任意多的源文件,文件名的名字也没有任何规定。
我是一名来自帝都985高校的机械研究生
本号专注于分享工科专业学习考试攻略、程序员学习求职经验、教师求职考试经验等相关内容,同时还会兼顾生活向,欢迎大家的关注和转发!