From 3daef20c2d9e51493db38d35f75cde81a4f92d40 Mon Sep 17 00:00:00 2001 From: Unknwon Date: Tue, 14 Jul 2015 23:44:28 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B2=BE=E6=A0=A1=EF=BC=9A5.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eBook/05.1.md | 2 +- eBook/05.2.md | 155 +++++++++++++++++++++++++++++--------------------- 2 files changed, 90 insertions(+), 67 deletions(-) diff --git a/eBook/05.1.md b/eBook/05.1.md index e6c1eae..6130f79 100644 --- a/eBook/05.1.md +++ b/eBook/05.1.md @@ -36,7 +36,7 @@ else-if 分支的数量是没有限制的,但是为了代码的可读性,还 关键字 if 和 else 之后的左大括号 `{` 必须和关键字在同一行,如果你使用了 else-if 结构,则前段代码块的右大括号 `}` 必须和 else-if 关键字在同一行。这两条规则都是被编译器强制规定的。 -非法的Go代码: +非法的 Go 代码: ```go if x{ diff --git a/eBook/05.2.md b/eBook/05.2.md index 87faadd..8cd1ea8 100644 --- a/eBook/05.2.md +++ b/eBook/05.2.md @@ -4,7 +4,9 @@ Go 语言的函数经常使用两个返回值来表示执行是否成功:返 在第 4.7 节的程序 `string_conversion.go` 中,函数 `strconv.Atoi` 的作用是将一个字符串转换为一个整数。之前我们忽略了相关的错误检查: - anInt, _ = strconv.Atoi(origStr) +```go +anInt, _ = strconv.Atoi(origStr) +``` 如果 origStr 不能被转换为整数,anInt 的值会变成 0 而 `_` 无视了错误,程序会继续运行。 @@ -12,46 +14,51 @@ Go 语言的函数经常使用两个返回值来表示执行是否成功:返 我们在第二个版本中对代码进行了改进: + 示例 1: -Example 5.3 [string_conversion2.go](examples/chapter_5/string_conversion2.go) +示例 5.3 [string_conversion2.go](examples/chapter_5/string_conversion2.go) - package main - - import ( - "fmt" - "strconv" - ) - - func main() { - var orig string = "ABC" - // var an int - var newS string - // var err error - - fmt.Printf("The size of ints is: %d\n", strconv.IntSize) - // anInt, err = strconv.Atoi(origStr) - an, err := strconv.Atoi(orig) - if err != nil { - fmt.Printf("orig %s is not an integer - exiting with error\n", orig) - return - } - fmt.Printf("The integer is %d\n", an) - an = an + 5 - newS = strconv.Itoa(an) - fmt.Printf("The new string is: %s\n", newS) - } +```go +package main + +import ( + "fmt" + "strconv" +) + +func main() { + var orig string = "ABC" + // var an int + var newS string + // var err error + + fmt.Printf("The size of ints is: %d\n", strconv.IntSize) + // anInt, err = strconv.Atoi(origStr) + an, err := strconv.Atoi(orig) + if err != nil { + fmt.Printf("orig %s is not an integer - exiting with error\n", orig) + return + } + fmt.Printf("The integer is %d\n", an) + an = an + 5 + newS = strconv.Itoa(an) + fmt.Printf("The new string is: %s\n", newS) +} +``` 这是测试 err 变量是否包含一个真正的错误(`if err != nil`)的习惯用法。如果确实存在错误,则会打印相应的错误信息然后通过 return 提前结束函数的执行。我们还可以使用携带返回值的 return 形式,例如 `return err`。这样一来,函数的调用者就可以检查函数执行过程中是否存在错误了。 **习惯用法** - value, err := pack1.Function1(param1) - if err!=nil { - fmt.Printf("An error occured in pack1.Function1 with parameter %v", param1) - return err - } - // 未发生错误,继续执行: +```go +value, err := pack1.Function1(param1) +if err!=nil { + fmt.Printf("An error occured in pack1.Function1 with parameter %v", param1) + return err +} +// 未发生错误,继续执行: +``` 由于本例的函数调用者属于 main 函数,所以程序会直接停止运行。 @@ -59,10 +66,12 @@ Example 5.3 [string_conversion2.go](examples/chapter_5/string_conversion2.go) **习惯用法** - if err !=nil { - fmt.Printf("Program stopping with error %v", err) - os.Exit(1) - } +```go +if err !=nil { + fmt.Printf("Program stopping with error %v", err) + os.Exit(1) +} +``` (此处的退出代码 1 可以使用外部脚本获取到) @@ -72,12 +81,14 @@ Example 5.3 [string_conversion2.go](examples/chapter_5/string_conversion2.go) 示例 2:我们尝试通过 `os.Open` 方法打开一个名为 `name` 的只读文件: - f, err := os.Open(name) - if err !=nil { - return err - } - doSomething(f) // 当没有错误发生时,文件对象被传入到某个函数中 - doSomething +```go +f, err := os.Open(name) +if err !=nil { + return err +} +doSomething(f) // 当没有错误发生时,文件对象被传入到某个函数中 +doSomething +``` **练习 5.1** 尝试改写 [string_conversion2.go](examples/chapter_5/string_conversion2.go) 中的代码,要求使用 `:=` 方法来对 err 进行赋值,哪些地方可以被修改? @@ -85,54 +96,66 @@ Example 5.3 [string_conversion2.go](examples/chapter_5/string_conversion2.go) **习惯用法** - if err := file.Chmod(0664); err !=nil { - fmt.Println(err) - return err - } +```go +if err := file.Chmod(0664); err !=nil { + fmt.Println(err) + return err +} +``` 示例 4:或者将 ok-pattern 的获取放置在 if 语句的初始化部分,然后进行判断: **习惯用法** - if value, ok := readData(); ok { - … - } +```go +if value, ok := readData(); ok { +… +} +``` **注意事项** 如果您像下面一样,没有为多返回值的函数准备足够的变量来存放结果: - func mySqrt(f float64) (v float64, ok bool) { - if f < 0 { return } // error case - return math.Sqrt(f),true - } +```go +func mySqrt(f float64) (v float64, ok bool) { + if f < 0 { return } // error case + return math.Sqrt(f),true +} - func main() { - t := mySqrt(25.0) - fmt.Println(t) - } +func main() { + t := mySqrt(25.0) + fmt.Println(t) +} +``` 您会得到一个编译错误:`multiple-value mySqrt() in single-value context`。 正确的做法是: - t, ok := mySqrt(25.0) - if ok { fmt.Println(t) } +```go +t, ok := mySqrt(25.0) +if ok { fmt.Println(t) } +``` **注意事项 2** 当您将字符串转换为整数时,且确定转换一定能够成功时,可以将 `Atoi` 函数进行一层忽略错误的封装: - func atoi (s string) (n int) { - n, _ = strconv.Atoi(s) - return - } +```go +func atoi (s string) (n int) { + n, _ = strconv.Atoi(s) + return +} +``` 实际上,`fmt` 包(第 4.4.3 节)最简单的打印函数也有 2 个返回值: - count, err := fmt.Println(x) // number of bytes printed, nil or 0, error +```go +count, err := fmt.Println(x) // number of bytes printed, nil or 0, error +``` -当打印到控制台时,可以将该函数返回的错误忽略;但当输出到文件流、网络流等具有不确定因素的输出对象时,应该始终检查是否有错误发生(另见 练习 6.1b)。 +当打印到控制台时,可以将该函数返回的错误忽略;但当输出到文件流、网络流等具有不确定因素的输出对象时,应该始终检查是否有错误发生(另见练习 6.1b)。 ## 链接