go语言笔记——多值函数,本质上和nodejs的回调很像,不过nodejs是回调的第一个参数是err,而golang里是第二个!
2017-05-16 15:13
573 查看
5.2 测试多返回值函数的错误
Go 语言的函数经常使用两个返回值来表示执行是否成功:返回某个值以及 true 表示成功;返回零值(或 nil)和 false 表示失败(第 4.4 节)。当不使用 true 或 false 的时候,也可以使用一个 error 类型的变量来代替作为第二个返回值:成功执行的话,error 的值为 nil,否则就会包含相应的错误信息(Go 语言中的错误类型为 error:var err error,我们将会在第 13 章进行更多地讨论)。这样一来,就很明显需要用一个 if 语句来测试执行结果;由于其符号的原因,这样的形式又称之为 comma,ok 模式(pattern)。
在第 4.7 节的程序
string_conversion.go中,函数
strconv.Atoi的作用是将一个字符串转换为一个整数。之前我们忽略了相关的错误检查:
anInt, _ = strconv.Atoi(origStr)
如果 origStr 不能被转换为整数,anInt 的值会变成 0 而
_无视了错误,程序会继续运行。
这样做是非常不好的:程序应该在最接近的位置检查所有相关的错误,至少需要暗示用户有错误发生并对函数进行返回,甚至中断程序。
我们在第二个版本中对代码进行了改进:
示例 1:
示例 5.3 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) }
这是测试 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 } // 未发生错误,继续执行:
由于本例的函数调用者属于 main 函数,所以程序会直接停止运行。
如果我们想要在错误发生的同时终止程序的运行,我们可以使用
os包的
Exit函数:
习惯用法
if err != nil { fmt.Printf("Program stopping with error %v", err) os.Exit(1) }
(此处的退出代码 1 可以使用外部脚本获取到)
有时候,你会发现这种习惯用法被连续重复地使用在某段代码中。
当没有错误发生时,代码继续运行就是唯一要做的事情,所以 if 语句块后面不需要使用 else 分支。
示例 2:我们尝试通过
os.Open方法打开一个名为
name的只读文件:
f, err := os.Open(name) if err != nil { return err } doSomething(f) // 当没有错误发生时,文件对象被传入到某个函数中 doSomething
练习 5.1 尝试改写 string_conversion2.go 中的代码,要求使用
:=方法来对 err 进行赋值,哪些地方可以被修改?
示例 3:可以将错误的获取放置在 if 语句的初始化部分:
习惯用法
if err := file.Chmod(0664); err != nil { fmt.Println(err) return err }
示例 4:或者将 ok-pattern 的获取放置在 if 语句的初始化部分,然后进行判断:
习惯用法
if value, ok := readData(); ok { … }
注意事项
如果您像下面一样,没有为多返回值的函数准备足够的变量来存放结果:
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) }
您会得到一个编译错误:
multiple-value mySqrt() in single-value context。
正确的做法是:
t, ok := mySqrt(25.0) if ok { fmt.Println(t) }
注意事项 2
当您将字符串转换为整数时,且确定转换一定能够成功时,可以将
Atoi函数进行一层忽略错误的封装:
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
当打印到控制台时,可以将该函数返回的错误忽略;但当输出到文件流、网络流等具有不确定因素的输出对象时,应该始终检查是否有错误发生(另见练习 6.1b)。
摘自:https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/05.2.md
相关文章推荐
- Golang学习笔记(2)---go语言基本类型
- 【golang】 go语言之环境搭建+ 第一个go语言程序
- go语言笔记——包的概念本质上和java是一样的,通过大小写来区分private,fmt的Printf不就是嘛!
- go语言笔记——append是内置的函数!!!new是一个函数!!!调试可以使用闭包,本质上是print调试,尼玛!
- golang实战使用gin+xorm搭建go语言web框架restgo详解5.6 控制器参数校验
- Go语言学习笔记(八)golang 操作 Redis & Mysql & RabbitMQ
- Go/Golang 语言学习笔记总结
- go语言笔记——切片底层本质是共享数组内存!!!绝对不要用指针指向 slice切片本身已经是一个引用类型就是指针
- golang实战使用gin+xorm搭建go语言web框架restgo详解3 系统常用配置参数
- golang实战使用gin+xorm搭建go语言web框架restgo详解5.4 控制器参数绑定
- 29.笔记go语言——函数多类型参数
- Go语言 golang 语法详解笔记
- go语言笔记——指针,和C用法以及本质一样,但不支持指针的+-运算!
- golang go语言 gomobile 移动端开发笔记
- 【GoLang笔记】浅析Go语言Interface类型的语法行为及用法
- [阅读笔记]Go语言并发之美
- Go语言Windows程序设计(2)--第一个窗口程序
- c#--编写一个名称为MyClass一个类,在该类中编写一个方法,名称为CountChar,返回值为整型,参数两个,第一个参数可以是字符串、整数、单精度、双精度,第二个参数为字符,方法功能返回第二个参
- go语言学习:web服务器 golang版
- go语言学习:web服务器 golang版