diff --git a/README.md b/README.md index 7b6df4f..3a36d59 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ ## 翻译进度 -6.3 [传递变长参数](eBook/06.3.md) +6.4 [defer 和追踪](eBook/06.4.md) ## 支持本书 -如果你喜欢本书 《Go入门指南》,你可以参与到本书的翻译或纠正工作中来,具体请联系【无闻 E-mail:joe2010xtmf#163.com】,一同完善本书并帮助壮大 Go 语言在国内的学习群体,给大家提供更好的学习资源。 +如果你喜欢本书 《Go入门指南》,你可以参与到本书的翻译或纠正工作中来,具体请联系【无闻 E-mail:u#gogs.io】,一同完善本书并帮助壮大 Go 语言在国内的学习群体,给大家提供更好的学习资源。 ## 交流社区 @@ -23,14 +23,11 @@ - 2012 年 3 月 28 日以前的博文中的内容基本过时,不要再看 - 符合等式 ***百度+思考+失败+翻墙+谷歌+尝试=解决*** 的问题最好不要发问 -- 不要问 Go 现在的发展前景如何 -- 不要问学习 Go 语言能不能找到工作 -- 不要问现在 Go 语言有哪些实际应用 ## 致谢 - 本书原作者:Ivo Balbaert -- 协助或参与翻译: +- 参与翻译人员: - [zhanming](https://github.com/zhanming) - [themorecolor](https://github.com/themorecolor) - [everyx](https://github.com/everyx) diff --git a/eBook/06.4.md b/eBook/06.4.md index 79d809f..e16247b 100644 --- a/eBook/06.4.md +++ b/eBook/06.4.md @@ -1,18 +1,237 @@ -## 啊哦,亲,你看得也太快了。。。还没翻译完呢 0 0 +# 6.4 defer 和追踪 -要不等到 **2014 年 8 月 4 日** 再来看看吧~~ +关键字 defer 允许我们推迟到函数返回之前(或任意位置执行 `return` 语句之后)一刻才执行某个语句或函数(为什么要在返回之后才执行这些语句?因为 `return` 语句同样可以包含一些操作,而不是单纯地返回某个值)。 -这里还有一些其它的学习资源噢~ +关键字 defer 的用法类似于面向对象编程语言 Java 和 C# 的 `finally` 语句块,它一般用于释放某些已分配的资源。 - - [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming) - - [《Go Web编程》](https://github.com/astaxie/build-web-application-with-golang) - - [《Go名库讲解》](https://github.com/Unknwon/go-rock-libraries-showcases) +下面这个示例很好地解释了它的用法(Listing 6.8 defer.go): -神马?你说你不想学习?那好吧,去逛逛看看行情也行~ +```go +package main +import “fmt” -- [Go Walker](https://gowalker.org) **Go 项目 API 文档在线浏览工具** -- [Golang Home](http://golanghome.com) -- [Go 语言学习园地](http://studygolang.com/) -- [Golang 中国](http://golangtc.com) +func main() { + Function1() +} -# 6.4 defer 和追踪 \ No newline at end of file +func Function1() { + fmt.Printf("In Function1 at the top\n") + defer Function2() + fmt.Printf("In Function1 at the bottom!\n") +} + +func Function2() { + fmt.Printf("Function2: Deferred until the end of the calling function!") +} +``` + +输出: + +``` +In Function1 at the top +In Function1 at the bottom! +Function2: Deferred until the end of the calling function! +``` + +请将 defer 关键字去掉并对比输出结果。 + +使用 defer 的语句同样可以接受参数,下面这个例子就会在执行 defer 语句时打印 `0`: + +```go +func a() { + i := 0 + defer fmt.Println(i) + i++ + return +} +``` + +当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出): + +```go +func f() { + for i := 0; i < 5; i++ { + defer fmt.Printf(“%d “, i) + } +} +``` + +上面的代码将会输出:`4 3 2 1 0`。 + +关键字 defer 允许我们进行一些函数执行完成后的收尾工作,例如: + +1. 关闭文件流: + + // open a file + defer file.Close() (详见第 12.2 节) + +2. 解锁一个加锁的资源 + + mu.Lock() + defer mu.Unlock() (详见第 9.3 节) + +3. 打印最终报告 + + printHeader() + defer printFooter() + +4. 关闭数据库链接 + + // open a database connection + defer disconnectFromDB() + +合理使用 defer 语句能够使得代码更加简洁。 + +以下代码模拟了上面描述的第 4 种情况: + +```go +package main + +import "fmt" + +func main() { + doDBOperations() +} + +func connectToDB() { + fmt.Println("ok, connected to db") +} + +func disconnectFromDB() { + fmt.Println("ok, disconnected from db") +} + +func doDBOperations() { + connectToDB() + fmt.Println("Defering the database disconnect.") + defer disconnectFromDB() //function called here with defer + fmt.Println("Doing some DB operations ...") + fmt.Println("Oops! some crash or network error ...") + fmt.Println("Returning from function here!") + return //terminate the program + // deferred function executed here just before actually returning, even if + // there is a return or abnormal termination before +} +``` + +输出: + +``` +ok, connected to db +Defering the database disconnect. +Doing some DB operations ... +Oops! some crash or network error ... +Returning from function here! +ok, disconnected from db +``` + +**使用 defer 语句实现代码追踪** + +一个基础但十分实用的实现代码执行追踪的方案就是在进入和离开某个函数打印相关的消息,即可以提炼为下面两个函数: + +```go + func trace(s string) { fmt.Println("entering:", s) } + func untrace(s string) { fmt.Println("leaving:", s) } +``` + +以下代码展示了何时调用两个函数: + +Listing 6.10—_defer_tracing.go: + +```go +package main + +import "fmt" + +func trace(s string) { fmt.Println("entering:", s) } +func untrace(s string) { fmt.Println("leaving:", s) } + +func a() { + trace("a") + defer untrace("a") + fmt.Println("in a") +} + +func b() { + trace("b") + defer untrace("b") + fmt.Println("in b") + a() +} + +func main() { + b() +} +``` + +输出: + +``` +entering: b +in b +entering: a +win a +leaving: a +leaving: b +``` + +上面的代码还可以修改为更加简便的版本(Listing 6.11—_defer_tracing2.go): + +```go +package main + +import "fmt" + +func trace(s string) string { + fmt.Println("entering:", s) + return s +} + +func un(s string) { + fmt.Println("leaving:", s) +} + +func a() { + defer un(trace("a")) + fmt.Println("in a") +} + +func b() { + defer un(trace("b")) + fmt.Println("in b") + a() +} + +func main() { + b() +} +``` + +**使用 defer 语句来记录函数的参数与返回值** + +下面的代码展示了另一种在调试时使用 defer 语句的手法(Listing 6.12—_defer_logvalues.go): + +```go +package main + +import ( + "io" + "log" +) + +func func1(s string) (n int, err error) { + defer func() { + log.Printf("func1(%q) = %d, %v", s, n, err) + }() + return 7, io.EOF +} + +func main() { + func1("Go") +} + +``` + +输出: + + Output: 2011/10/04 10:46:11 func1(“Go”) = 7, EOF \ No newline at end of file diff --git a/eBook/06.5.md b/eBook/06.5.md new file mode 100644 index 0000000..f675b5f --- /dev/null +++ b/eBook/06.5.md @@ -0,0 +1,3 @@ +# 6.5 内置函数 + +142 \ No newline at end of file