GO 指南笔记
12 Jul 2016零值
- 数值类型为
0
- 布尔类型为
false
- 字符串为 “” (空字符串)
常量
- 常量定义与变量类似,只不过使用
const
关键字 - 常量不能用
:=
语法定义
数值常量
- 数值常量是高精度的 值 。
- 一个未指定类型的常量由上下文来决定其类型。
const (
Big = 1 << 100
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func main() {
fmt.Println(needFloat(Big))
}
switch
- 除非以
fallthrough
语句结束,否则分支会自动终止。
defer
- defer 语句会延迟函数的执行直到上层函数返回。
- 延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用。
- 延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。
func main() {
i := 1
defer fmt.Println("world", i)
i++
fmt.Println("hello", i)
}
//hello 2
//world 1
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
指针
- 指针保存了变量的内存地址
- 类型 *T 是指向类型 T 的值的指针。其零值是 nil 。
- & 符号会生成一个指向其作用对象的指针。
- 符号表示指针指向的底层的值
结构体
- 结构体字段可以通过结构体指针来访问
- 指针简介的访问时透明的
- 前缀
&
返回一个指向结构体的指针
数组
- 类型
[n]T
是一个有n
个类型为T
的值的数组 - 数组不能改变大小
slice
- 一个 slice 会指向一个序列的值,并且包含了长度信息
[]T
是一个元素类型为T
的slice
len(s)
返回 slice s 的长度- 作为变长数组的替代方案,可以管理底层数组的局部或全部
对 slice 切片
s[lo:hi]
表示从 lo 到 hi-1 的 slice 元素,含开始下标,不包含结束下标make
创建 slice,会分配一个全是零值的数组并且返回一个 slice 指向这个数组- 第三个参数是制定容量
- slice 的零值是 nil
- 一个 nil 的 slice 的长度和容量是 0。
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
range
for 循环的 range 格式可以对 slice 或者 map 进行迭代循环
map
在 map m 中插入或修改一个元素: m[key] = elem
获得元素:elem = m[key]
删除元素:delete(m, key)
通过双赋值检测某个键存在:elem, ok = m[key]
函数
- 函数值可以作为函数的参数或者返回值
- Go 函数可以是一个闭包
方法
有两个原因需要使用指针接收者。
- 首先避免在每个方法调用中拷贝值(如果值类型是大的结构体的话会更有效率)。
- 其次,方法可以修改接收者指向的值
type Vertex struct {
X, Y float64
}
// 使用指针接收者,是为了避免在调用方法中拷贝值,其次是可以修改接受者指向的值
// 因为值类型可能是大的结构体,拷贝的话性能不好
// 如果 v 是一个值(非指针),方法看到的是 Vertex 的副本,并且无法修改原始值
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Println(v.Abs())
}
接口
- 接口类型是由一组方法定义的集合。
- 接口类型的值可以存放实现这些方法的任何值。
Stringers
Stringer 是一个可以用字符串描述自己的类型。fmt
包 (还有许多其他包)使用这个来进行输出。
type Stringer interface {
String() string
}
错误
与 fmt.Stringer 类似, error 类型是一个内建接口:
type error interface {
Error() string
}
Goroutine
goroutine 是由 Go 运行时环境管理的轻量级线程。
channel
- channel 是有类型的管道
- 可以用 channel 操作符 <- 对其发送或者接收值。
- 默认情况下,在另一端准备好之前,发送和接收都会阻塞。这使得 goroutine 可以在没有明确的锁或竞态变量的情况下进行同步
缓冲 channel
- channel 可以是 带缓冲的。为 make 提供第二个参数作为缓冲长度来初始化一个缓冲
- 向带缓冲的 channel 发送数据的时候,只有在缓冲区满的时候才会阻塞。
- 而当缓冲区为空的时候接收操作会阻塞。
ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3 //因为缓存区比填满,fatal error: all goroutines are asleep - deadlock!
fmt.Println(<-ch)
fmt.Println(<-ch)
range 和 close
- 发送者可以 close 一个 channel
v, ok := <-ch
- 接收者可以通过赋值语句的第二参数来测试 channel 是否被关闭
- 当没有值可以接收并且 channel 已经被关闭,那么取值之后 ok 会被设置为 false
for i := range c
- 循环 会不断从 channel 接收值,直到它被关闭
注意事项
- 只有发送者才能关闭 channel,而不是接收者
- 向一个已经关闭的 channel 发送数据会引起 panic
- channel 与文件不同;通常情况下无需关闭它们
- 只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个 range
select
- select 语句使得一个 goroutine 在多个通讯操作上等待。