Golang Basic
Golang 基础
下划线
在Golang之中,import
用于引入其他package,其作用是当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已。这个时候就可以使用 import
引用该包。即使用import _ 包路径
只是引用该包,仅仅是为了调用init()
函数,所以无法通过包名来调用包中的其他函数。
目录数如下:
此外还可以:
变量和常量
变量
变量声明:
变量初始化:
短变量声明赋值:
匿名变量:
:warning: 注意:
函数外的每个语句都必须以关键字开始(var、const、func等)
:=
不能使用在函数外
_
多用于占位,表示忽略值
常量
常量声明并赋值:
iota
iota是golang语言的常量计数器,只能在常量的表达式中使用。iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。使用iota能简化定义,在定义枚举时很有用。
定义数量级:
数据类型
更多参考:https://www.geeksforgeeks.org/data-types-in-go/
String
赋值多行字符串给变量:
字符串处理及函数参考[./String Operate](./String Operate.md)
byte和rune类型
Go 语言的字符有以下两种:
- uint8类型:或者叫 byte 型,代表了ASCII码的一个字符。
- rune类型:代表一个 UTF-8字符,用于处理中文、日文或者其他复合字符
数组
一维数组
二维数组
:warning: range
创建了每个元素的副本,而不是直接返回对该元素的引用。
切片Slice
切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append() 来实现的,这个函数可以快速且高效地增长切片,也可以通过对切片再次切割,缩小一个切片的大小。因为切片的底层也是在连续的内存块中分配的,所以切片还能获得索引、迭代以及为垃圾回收优化的好处。
需要说明,slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。
切片声明赋值
切片的创建方式与数组的创建方式类似,区别是切片创建时[]
没有数值,有数值则为数组。
:warning: Golang 不允许创建容量小于长度的切片。
通过切片创建新的切片
通过切片创建新切片的语法如下:
其中 i 表示从 slice 的第几个元素开始切,j 控制切片的长度(j-i),k 控制切片的容量(k-i),如果没有给定 k,则表示切到底层数组的最尾部。下面是几种常见的简写形式:
让我们通过下面的例子来理解通过切片创建新的切片的本质:
执行上面的代码后,我们有了两个切片,它们共享同一段底层数组,但通过不同的切片会看到底层数组的不同部分:
:information_source:截取新切片时的原则是 “左含右不含”。所以 newNum 是从 myNum 的 index=1 处开始截取,截取到 index=3 的前一个元素,也就是不包含 index=3 这个元素。所以,新的 newNum 是由 myNum 中的第2个元素、第3个元素组成的新的切片构,长度为 2,容量为 4。切片 myNum 能够看到底层数组全部 5 个元素的容量,而 newNum 能看到的底层数组的容量只有 4 个元素。newNum 无法访问到底层数组的第一个元素。所以,对 newNum 来说,那个元素就是不存在的。
切片扩容
如果切片的底层数组没有足够的可用容量,append() 函数会创建一个新的底层数组,将被引用的现有的值复制到新数组里,再追加新的值,此时 append 操作同时增加切片的长度和容量:
当这个 append 操作完成后,newSlice 拥有一个全新的底层数组,这个数组的容量是原来的两倍:
函数 append() 会智能地处理底层数组的容量增长。在切片的容量小于 1000 个元素时,总是会成倍地增加容量。一旦元素个数超过 1000,容量的增长因子会设为 1.25,也就是会每次增加 25%的容量(随着语言的演化,这种增长算法可能会有所改变)。
将一个切片追加到另外一个切片:
遍历切片
切片拷贝
它表示把切片 src 中的元素拷贝到切片 dst 中,返回值为拷贝成功的元素个数。如果 src 比 dst 长,就截断;如果 src 比 dst 短,则只拷贝 src 那部分:
运行这段单面,输出的结果为:
3 表示拷贝成功的元素个数。
将切片传递给函数
map映射
映射是一个数据集合,所以可以是使用类似处理数组和切片的方式来迭代映射中的元素。但映射是无序集合,所以即使以同样的顺序保存键值对,迭代映射时,元素的顺序可能会不一样。无序的原因是映射的实现使用了哈希表。
与切片类似,可以通过声明一个未初始化的映射来创建一个值为 nil 的映射(一般称为 nil 映射),nil 映射不能用于存储键值对:
运行这段代码会产生一个运行时错误:panic: assignment to entry in nil map
映射CRUD
遍历映射
将映射传递给函数
map容量
和数组不同,map 可以根据新增的 key-value 动态的伸缩,因此它不存在固定长度或者最大限制,但是也可以选择标明 map 的初始容量 capacity,格式如下:
当 map 增长到容量上限的时候,如果再增加新的 key-value,map 的大小会自动加 1,所以出于性能的考虑,对于大的 map 或者会快速扩张的 map,即使只是大概知道容量,也最好先标明。
用切片作为 map 的值
既然一个 key 只能对应一个 value,而 value 又是一个原始类型,那么如果一个 key 要对应多个值怎么办?例如,当我们要处理 unix 机器上的所有进程,以父进程(pid 为整形)作为 key,所有的子进程(以所有子进程的 pid 组成的切片)作为 value。通过将 value 定义为 []int 类型或者其他类型的切片,就可以优雅的解决这个问题,示例代码如下所示:
多维映射
流程控制及循环
if
:warning: 不支持三元操作符(三目运算符) "a > b ? a : b"
。
switch
type switch
select
select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。select 是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。 select 随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。
for
range
Golang range类似迭代器操作,返回 (索引, 值) 或 (键, 值)。
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for 和 for range有什么区别?
主要是使用场景不同,for可以
- 遍历
array
和slice
- 遍历key为整型递增的
map
- 遍历
string
for range
可以完成所有for可以做的事情,却能做到for不能做的,包括:
遍历key为
string
类型的map
并同时获取key和value遍历
channel
goto
Label
在 break
和 continue
语句中是可选参数,而在 goto
语句中是必传的参数。Label
只在声明它的函数中有效。只要函数中声明了 Label
,那它在该函数的整个作用域都有效。
Label
的标识符和其他标识符具有不同的命名空间,所以不会与变量标识符等发生冲突。下面这段代码同时在 Label
和变量声明中都使用 x
作为标识符:
死循环
golang死循环的几种写法:
参考链接
-
Go 语言中文文档:http://www.topgoer.com/
-
Go 语言中文网:https://studygolang.com/
-
【引用】Golang 切片入门https://www.cnblogs.com/sparkdev/p/10704614.html
-
Golang 映射入门:https://www.cnblogs.com/sparkdev/p/10749542.html