Go程序设计语言读书笔记-第四章

第四章-复合数据类型

数组:由于数组的长度固定,所以在Go里面很少用。

var a [3]int 
fmt.Println(a[0])
fmt.Println(a[len(a)-1])

//输出索引和元素
for i,v := range a{
 fmt.Printf("%d %d\n",i,v)
}

//初始化数组
var q [3]int = [3]int{1,2,3}
var r [3]int = [3]int{1,2}

//q可以简化为:
q := [...]int{1,2,3}

如果省略号"..."出现数组长度位置,那么数组的长度由初始化元素的个数决定。数组长度是数组类型的一部分,所以[3]int和[4]int是两种不同的数组类型。在编译时确定。

r :=[...]int{99:-1}

定义了一个拥有100个元素的数组r,除了最后一个元素值是-1外,该数组中的其他元素值都是0.

如果一个数组的元素类型是可比较的,那么这个数组也是可比较的。

a:= [2]int{1,2}
b := [...]int{1,2}
c :=[2]int{1,3}
fmt.Println(a == b,a == c,b == c)  //true false false
d :=[3]int{1,2}
fmt.Println(a == d)  //编译错误,无法比较[2]int == [3]int

调用函数的参数传递,Go把数组和其他类型都看成值传递。

切片,Slice:slice有三个属性:指针,长度、和容量。
指针指向数组第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素,长度是slice中元素的个数,容量的大小通常是从slice的起始元素到底层数组的最后一个元素间元素的个数。Go的内置函数len和cap用来返回slice的长度和容量。

s :=[]int{0,1,2,3,4,5}

slice没有指定长度。和数组不同的是,slice无法做比较(用==)。标准库里面提供了bytes.Equal来比较两个字节slice([]bytes)。但是对于其他类型的slice,必须自己写函数来比较。

slice唯一允许的比较操作是和nil做比较:

if summer == nil{....}

var s []int   //len(s) == 0,s==nil
s = nil   //len(s) ==0,s == nil
s = []int(nil)   //len(s) == 0, s == nil
s = []int()   //len(s) == 0,s != nil

所以,想要检查一个slice是否为空,使用len(s) == 0而不是s==nil.

如果slice的引用超过了被引用对象的容量,即cap(s),那么会导致宕机;但是如果slice的引用超出了被引用对象的长度,即len(s),那么最终slice会比原来slice长。

append函数:内置函数append用来将元素追加到slice的后面。

var runes []rune
for _,r := range "Hello,世界"{
  runes = append(runes,r)
}

fmt.Printf("%q\n",runes)    //"['H' 'e' 'l' 'l' 'o' ',' ' ' ' ' '世' '界']"

通常情况下,我们不清楚一次append调用会不会导致一次新的内存分配,所以我们不能假设原始的slice和调用append后的结果指向同一个底层数组,也无法证明他们就指向不同的底层数组。同样,我们也无法假设旧slice上对元的操作会或者不会影响新的slice元素。所以,通常我们将append的调用结果再次赋值给传入append函数的slice:

runes = append(runes,r)

对于任何函数,只要有可能改变slice的长度或者容量,抑或是使得slice指向不同的底层数组,都需要更新slice变量。必须记住,虽然底层数组的元素似乎简介引用的,但是slice二点指针、长度和容量不是。

map:是散列表的引用,map的类型是map[k]v。键的类型k,必须是可以通过操作符==进行比较的数据类型,所以map可以检测某一个键是否已经存在。

内置函数make可以用来创建一个map

ages := make(map[string]int)  //创建一个string到int的map

ages := map[string]int{
	"alice": 31,
	"charlie": 34,
}

等价于

ages :=make(map[string]int)
ages["alice"] = 31
ages["charlie"] = 34

可以使用内置函数delete来从字典中根据键移除一个元素:

delete(ages,"alice")   //移除元素ages["alice"]

即使键不在map中,上面的操作也是安全的。map使用给定的键来查找元素,如果键不存在,就返回值类型的零值。

ages["bob"] = ages["bob"] + 1

//Golang判断key是否在map中
if _, ok := map[key]; ok {  

} 

map遍历:

for name,age := range ages{
	fmt.Printf("%s\t%d\n",name,age)
}

map中元素迭代顺序是不固定的,不同的实现方法会使用不同的散列算法,得到不同的元素顺序。实践中,我们认为是随机的。如果按照某种顺序来遍历map中的元素,我们必须显示地给键排序。可以使用sort包中的Strings函数,这是常见的模式:

var names []string
//或者 names := make([]string,0,len(ages))

fot name:= range ages{
	names = append(names,name)
}

sort.Strings(names)

for _,name := range names{
	fmt.Printf("%s\t%d\n",name,ages[name])
}

其实按key排序需要取出key,对key排序,再遍历输出value。
设置元素之前,必须初始化map。
未初始化的map是nil,它与一个空map基本等价,只是nil的map不允许往里面添加值。
因此,map是nil时,取值是不会报错的(取不到而已),但增加值会报错。

猜你喜欢

转载自blog.csdn.net/Rage_/article/details/89310303