【Go 学习笔记】3 – Go 数组 字典
分组声明
同时声明多个变量,常量,或者导入多个包时,可以采用分组的方式进行声明
import(
"fmt"
"os"
)
# 除非被显式设置为其他值或是iota,每个const分组的第一个常量被默认设置为他的0值
# 第二及后续的常量被默认设置为它前面那个常量的值。
# 如果前面那个常量的值是 iota ,则它也被设置为 iota
const(
i = 100
pi = 3.1415
value = name
)
var(
i int
pi float32
value string
)
IOTA 枚举
iota 这个关键字用来声明 enum
的时候采用。它默认从 0
开始,每次调用加 1
;
const(
x = iota // x == 0
y = iota // y == 1
z = iota // z == 2
w //常量声明省略时,默认和之前一个值的字面相同。这里w = iota =3
)
# 遇到一个const关键字,iota就会重置。这里 v == 0
const v = iota
# iota 在同一行的时候,值相同
const(
// 这里 e == f == g == 0
e, f, g = iota, iota, iota
)
array 数组
定义方式: var arr [n]tpye
[n]type
n
代表数组长度,tpye
表示存储元素的类型。
对数组的操作 都是通过[]
来进行处理的。
var arr [10]int
arr[0] = 42 // 数组下标从 0 开始
arr[1] = 13
fmt.Printf("The first element is %d\n",arr[0])
// 获取一个未赋值的最后一个元素,默认返回 0
fmt.Printf("The last element is %d\n",arr[9])
由于长度也是数组的一部分,所以,[3]int
和 [4]int
是不同的类型。
数组是不能改变长度的。
数组之间的赋值 是值的赋值,即当把一个数组作为参数传入函数的时候,传入的其实是这个数组的副本,而不是指针。如果要使用指针,就需要用到 slice 类型。
数组也可以使用 :=
来声明
a := [3]int{1, 2, 3}
//声明长度为10的数组,前三个元素值是1,2,3 其他默认为 0
b := [10]int{1,2,3}
// 可以省略长度,采用... 的方式。go会根据元素来确定数组长度。
c := [...]int{4,5,6}
嵌套数组
//声明一个二维数组,这个数组有两个元素,每个元素又是由4个int类型元素组成
doubleArray := [2][4]int{[4]int{1,2,3,4}, [4]int{5,6,7,8}}
//嵌套数组的简化声明。
easyArray := [2][4]int{{1,2,3,4}, {5,6,7,8}}
SLICE
slice 不是真正意义上的动态数组,是一个引用类型。
slice 总是指向一个底层 array slice 的声明和array一样,只是 不需要长度
命令: var sli []int
赋值: slice := []bypt{'a', 'b','c'}
slice 可以从一个数组或是一个已经存在的 slice 中再次声明。 slice 通过 array[i:j]
来获取,其中i
是数组的开始位置,j
是结束位置。但是不包括 j
他的长度是j-i
var ar = [10]int{1,2,3,4,5,6,7,8,9,0}
// 声明两个含有 int 的slice
var a, b []int
// a 含有的元素是 ar[2] ar[3] ar[4]
a = ar[2:5]
// b 含有的元素是 ar[3] ar[4]
b = ar[3:5]
slice 的默认开始位置是 0 , ar[:n] 等价于 ar [0:n]
slice 的第二个序列默认是数组的长度,ar[n:] 等价于 ar[n:len(ar)]
如果从一个数组之间获取slice,可以写为: ar[:]
slice
和array
的区别:声明数组时,方括号内写明了数组的长度或是使用 ...
自动计算长度。
声明slice的时候,方括号内没有任何的字符
。
简单操作
var array = [10]byte{'a','b','c','d','e','f','g','h','i','j'}
var aslice, bslice []byte
aslice = array[:3] //
aslice = array[5:] //
aslice = array[:] //
aslice = array[3:7] // 包含了 d,e,f,g len=4 cap=7
bslice = aslice[1:3] // aslice[1] aslice[2]
bslice = aslice[:3] // aslice[0] aslice[1] aslice[2]
bslice = aslice[0:5] // aslice可以在cap范围内扩展。所以结果是:d,e,f,g,h
bslice = aslice[:] // 包含了aslice所有元素
从概念上说,slice 像一个结构体,它包含了三个元素。
一个指针,指向了数组中slice开始的位置。
长度: slice的长度
最大长度: 也就是slice开始位置到数组的最后位置的长度,即cap
// 如上例,这里aslice的len=4,bslice这里取了5个元素,所以aslice要在cap的范围内扩展
bslice = aslice[0:5]
slice 的内置函数
len 获取 slice 的长度
cap 获取 slice 的最大长度
append 向 slice 里追加一个或多个元素。
copy 从源 slice 的 src 中复制元素到目标,并返回复制元素的 个数。
注意:
append 会改变 slice 所引用数组的内容,从而影响到引用统一数组的其他slice
当slice 没有剩余空间(cap-len==0) 这时将动态分配新的数组空间。
返回的slice数组指针将指向新的空间。原数组的内容将保持不变。其他引用此数组的slice不受影响。
map
map 字典 格式 map[keyTpye]valueTpye
map 通过key
来操作。key有很多类型,可以是int,也可以是string 以及所有定义了 ==
和!=
操作的类型。
var number map[string]int
// 另外一种声明方式
numbers := make(map[string]int)
numbers["one"] = 1
numbers["two"] = 2
numbers["three"] = 3
fmt.Printf("第二个数是: ",numbers["two"])
注意
map 是无序的,不是通过 index 获取,是通过 key 获取
map 的长度不固定。也是一种引用类型,和slice一样。
内置的len 适用于map。其作用是返回 map 中key的数量。
map 的值可以修改。例如numbers["ont"] = 12 就把one的字典值改成了11
map 初始化可以通过 key:val 的方式初始化,同时map内置有判断是否存在key的方式。
*** map 不是 three-safe,才多个goroutine存取的是,必须使用 mutex lock 机制。
map 的删除
rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2}
// map 有两个返回值,第二个返回值,如果不存在key,则ok是false,如果存在,ok是true
csharpRating, ok := rating["C#"]
if ok {
fmt.Println("C# is in the map and ist rating is ", csharpRating)
} else {
fmt.Println("We have no rating associated with C# in the map")
}
// 删除 key 为C的元素
delete(rating, "C")
// 打印字典
fmt.Println(rating)
make new
make 用于内建类型(map slice channel
)的内存分配。
new 用于各种类型的内存分配。
new(T)
分配了零值填充的 T
类型的内存空间,并返回其地址,即一个*T
类型的值。 new 返回了一个指针
make(T, args) 和new有不同的功能,其返回一个有初始值的 T 类型。这是因为指向数据结构的引用在使用前必须被初始化。make 初始化了内部数据结构,填充适当的值,make 返回了一个初始化后的值(非零)
关于“零值” 并不是 空值
。 是一种 变量未赋值前的默认值
,通常为0
# 这里列出了部分类型的 零值
int 0
int8 0
int32 0
int64 0
uint 0x0
rune 0 //rune的实际类型是 int32
byte 0x0 // byte的实际类型是 uint8
float32 0 //长度为 4 byte
float64 0 //长度为 8 byte
bool false
string ""