Day 2:
Go语言存在指针类型,指针保存了值的内存地址,
*T表示指向类型T的指针,其空值为nil
&操作符生成一个指向操作数的指针
*操作符表示指针的值
和C语言不同,Go没有指针算法
Go和C一样也有结构体Structs,结构体是元素的集合
访问结构体的成员变量(字段)的方法是使用点
结构体字段可以通过结构体指针访问
结构体字面量(literals)有点类似于Python中对类的实例化,众所周知Go中没有class关键字
Go中的数组和Python中的列表和元组很像,不过在声明数组时需要指定数组的长度以及数组值的类型
数组是定长的,因而其使用收到很大限制,切片可以看成是变长的数组,切片规则和python一致为半开区间
切片类似为对数组的引用,它不存储任何数据,只描述数组。对切片所指的数据进行修改,会影响到:
- 源数组
- 其他引用该数组的切片
切片字面量类似于没有长度的数组字面量
// 数组字面量
[3]bool{true, true, false}
// 切片字面量
[]bool{true, true, false}
切片默认值就是在切片左右边界值缺失时的默认值,切片默认值和Python中的一样,左边界默认为0,右边界默认为切片长度
切片的长度和容量是切片的两个属性
- 长度是指切片中元素的个数
- 容量是指基础数组的元素个数,从切片中第一个元素开始计算
所以就造成s[2:]会改变切片的容量
使用len(s)、cap(s)分别获取切片的长度和容量
可以通过重切片来增加切片的长度,但是需要在可用的容量范围内,如果超出容量范围则会报错
panic: runtime error: slice bounds out of range [:10] with capacity 4
这部分内容和Python的不太一样,需要多理解一下
注意:你可能不太理解为什么第19行输出的会是[5 7]而不是[5 7 11 13],这是因为此时的s长度为4、容量为6,而切片右默认值为切片的长度,所以第19行输出的其实是[2:4]
切片的空值为nil,空的切片长度和容量都为0,并且没有基础数组
切片可以通过内置函数make生成,这是生成动态长度数组的方式
语法为make([]{T}, {len}, {cap})
a := make([]int, 0, 5) //len(a)=0, cap(a)=5
注意,cap可以缺省,缺省则cap(a) = len(a)
切片元素可以是任何类型,甚至包含其他切片,这有点类似Python中列表包含列表
三维切片:
package main
import (
"fmt"
)
func main() {
// Create a tic-tac-toe board.
board := [][][]string{
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
[][]string{
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
[]string{"_", "_", "_"},
},
}
fmt.Println(board)
}
[[[_ _ _] [_ _ _] [_ _ _]] [[_ _ _] [_ _ _] [_ _ _]] [[_ _ _] [_ _ _] [_ _ _]]]
Go提供内置函数append来给切片添加元素,类似Python列表的append方法。
如果切片s的基本数组容量不够接收新元素,则新的切片会指向新的数组
for循环的range形式使得能够在切片或字典上进行迭代,每次迭代返回两个值,第一个为索引,第二个为该索引对应值的拷贝。这点与Python中的range形式不太一样,反而和enumerate比较相似
和Python中类似,可以用单下划线代表不需要的变量
如果只想要索引,而不想要值,则可以将第二个变量完全省略
这个练习很容易理解,就是要让你构造一个长度为dy,每个元素为dx长度切片的切片,切片中的切片元素中的每个元素为函数(x+y)/2,x*y和x^y的值。但令人迷惑的是main函数中传入pic.Show函数的是Pic函数,而Pic函数并没有传入dx和dy参数,ex为此有人在GitHub上发了个issue
https://github.com/golang/tour/issues/1042
具体原因就是pic.Show这个函数很特殊,看完源码就能理解了https://github.com/golang/tour/blob/master/pic/pic.go#L27
func Show(f func(dx, dy int) [][]uint8) {
const (
dx = 256
dy = 256
)
data := f(dx, dy)
m := image.NewNRGBA(image.Rect(0, 0, dx, dy))
for y := 0; y < dy; y++ {
for x := 0; x < dx; x++ {
v := data[y][x]
i := y*m.Stride + x*4
m.Pix[i] = v
m.Pix[i+1] = v
m.Pix[i+2] = 255
m.Pix[i+3] = 255
}
}
ShowImage(m)
}
和Python一样,Go也有map,为了和Python的字典区别开,我们称其为映射,基于哈希表的键值映射
映射的0值为nil,nil映射没有键而且不能添加键,使用make方法可以返回能够使用的映射
注意:通过
var m map[string]Vertex
声明的映射m无法使用,因为是nil映射,需要
m = make(map[string]Vertex)
此时才能添加键
在结构体字面量前加上键就成了映射字面量
如果顶级类型仅是一个类型名,则元素中字面量的类型名可以省略
- 插入或者更新元素:
m[key] = elem
- 检索一个元素:
elem = m[key]
- 删除一个元素
delete(m, key)
- 测试映射中是否存在某键
elem, ok = m[key]
如果存在则elem为值,ok为true;如果不存在则elem为元素对应类型的0值,ok为false
这个练习是要统计所给字符串中单词的出现次数,需要使用strings.Fields方法
函数也是值,所以可以像其他值一样被传递
函数值也可以当作函数参数并且返回值
Go的函数可以是闭包。
关于闭包可以参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
https://www.zhihu.com/question/34210214
使用闭包生成斐波那契数列