今日班车看书时间的收获:
1. 程序中每个代码文件里的init函数,都会在main函数执行前被调用
2. 引用类型要用make来构造,比如map、channel
3. 标识符,首字母大写,就能被包外的代码访问。(公开)
4. 用空白标识符,“_”,放在导入的包前面。可以在不调用该包函数的前提上,调度运行其中的init函数。
eg
package postgres
import (
"database/sql"
)
func init () {
sql.Register("postgres", new(PostgresDriver)) //create a instance of postgres driver
}
package main
import (
"database/sql"
_ "github.com/goinaction/code/chapter3/dbdriver/postgres"
)
func main() {
sql.Open("postgres", "mydb")
}
5. "github.com/goinaction/code/chapter3/words" CountWords
6. go build / go run
7. go vet / go fmt / go doc tar || go doc -http=:6060
8. 依赖管理vendor、godep、gopkg.in
defer的用法(延时调用函数(Deferred Function Calls)):
首先要明确的是:
1. defer是在return之前执行的
这是官方文档中明确说明的http://golang.org/ref/spec#Defer_statements
2. go返回值的方式跟C是不一样的,为了支持多值返回,go是用栈返回值的,而C是用寄存器
3. return xxx 这一句语句并不是一条原子指令
所以,整个return过程,没有defer之前是,先把在栈中写一个值,这个值被会当作返回值。然后再调用RET指令返回。return xxx语句汇编后是先给返回值赋值,再做一个空的return: ( 赋值指令 + RET指令)
defer的执行是被插入到return指令之前的
有了defer之后,就变成了 (赋值指令 + CALL defer指令 + RET指令)
改写规则是将return语句分开成两句写,return xxx会被改写成:
返回值 = xxx
调用defer函数
空的return
example1
func f() (result int) {
defer func() {
result++
}()
return 0
}
example2
func f() (r int) {
t := 5
defer func() {
t = t + 5
}()
return t
}
example3
func f() (r int) {
defer func(r int) {
r = r + 5
}(r)
return 1
}
1 5 1
如果有多个defer 调用, 则调用的顺序是先进后出的顺序, 类似于入栈出栈一样:
func main(){
deferfmt.Println(1)
deferfmt.Println(2)
deferfmt.Println(3)
deferfmt.Println(4)
}
最先执行的是 "fmt.Println(4)", 接着是 "fmt.Println(3)" 依次类推, 最后的输出如下:
4321
需要注意的是, defer 调用的函数参数的值 defer 被定义时就确定了;而 defer 函数内部所使用的变量的值需要在这个函数运行时才确定
例如:
i := 1
defer fmt.Println("Deferred print:", i)
i++
fmt.Println("Normal print:", i)
打印的内容如下:
Normal print:2
Deferred print:1
defer 表达式的使用场景
defer 通常用于 open/close, connect/disconnect, lock/unlock 等这些成对的操作, 来保证在任何情况下资源都被正确释放.
var mutex sync.Mutex
var count=0
func increment() {
mutex.Lock()
defer mutex.Unlock()
count++
}
网友评论