指针
Go也有指针
·
p := 2
pInt := &p //定义一个指针变量,赋值为变量p的地址,编译器可以自动识别
fmt.Printf("p=%d\tpInt=%p\n",p,pInt)
*pInt = 123445
fmt.Printf("p=%d\tpInt=%p\n",p,pInt)
输出
p=2 pInt=0x12060140
p=123445 pInt=0x12060140
函数在前面说过了,这里说一下函数的调用
不定参数
不定参数是指函数传入的参数个数为不定数量 首先需要将函数定义成接受不定参数类型 func myFunc(args ...int){ for _,arg:= range args{ fmt.Println(arg) } } 或者为 func myFunc(args []int){ ........... } 如果想不限定传递参数的类型,可以指定interface{} 如Go语言标准库中的fmt.Printf()函数 func Printf(format string,args ...interface{}){ //.... }
函数返回多个值
Go语言也提供了像Python一样返回多个值语法,一般来说Go中很多package都返回两个值,一个是正常期望返回的值,一个是错误error.
比如File.Read()函数可以同时返回读取的字节数和错误信息 func (file *File)Read(b []byte)(n int,err Error)
匿名函数
匿名函数指的是不需要定义函数名的一种函数实现方式
f := func (a,b int,z float64) bool{ return a*b < int(z) } 可以赋给一个变量或者直接执行
闭包
闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及他们引用的对象,没有被释放)为自由变量提供绑定的计算环境(作用域)。
package main import "fmt" func main(){ var j int = 5 a := func()(func()){ var i int = 10 return func(){ fmt.Println("i, j: %d\n",i ,j) } }() a() j*=2 a() } 输出 i, j: 10,5 i, j: 10,10
错误处理
Go中引入了一个错误处理的标准模式,error接口
type error interface{ Error() string }
在Go中大多函数,如果要返回错误,大致上都可以定义为如下模式,将error作为多种返回值中的最后一个,当然这个并非是强制要求(怎么看都有点javascript的感觉,哈哈)。
func myFunc(param string)(str string,err error){ //... } 调用时的代码 n, err := myFunc("") if err := nil { //... }else{ //... } 那如何应用到实际中呢? 在Go中,接口的实现,根本不需要明确类型和接口之间的关系 type myError struct{ msg string } 要想让编译器知道myError可以当做一个error来处理,这个时候就要去实现Error()方法了 func (e *myError)Error()string{ return e.msg } 例子 func myFunc(name string)(string,error){ if len(name)<10 { return name+" is right",nil }else{ return name+" is not right",&myError("incorrect!") } }
defer
defer的出现简直就是C/C++程序员的福音,在程序中,特别是在调用一个资源的时候,比如数据库连接,但是程序出现异常的地方可能有很多,每一个可能的地方都有一个return的位置,该关闭的可能就没有来得及关闭,使用defer就可以很轻松解决这个问题,而且增加代码的可读性和优雅性。
func CopyFile(dst,src string)(w int64, err error){ srcFile, err := os.Open(src) if err != nil{ return } defer srcFile.CLose() } dstFile,err := os.Create(dst) if err != nil { return } defer dstFile.Close() return io.COpy(dstFile,srcFile) } 即使其中Copy()函数抛出异常,Go仍然会保证dstFile和srcFile被正常关闭。 一个函数里面可以有多个defer,他们按照栈的方式执行,先进后出
panic()和recover()
Go语言引入了两个内置函数panic()和recover()以报告和处理运行时错误和程序中的错误场景。
func panic(interface())
func recover(interface())
当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数终止之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数终止,错误信息将被上报,包括panic()函数传入的参数。
recover()函数用于终止错误处理流程。一般情况下,recover()应该在一个使用defer关键字的函数中执行有效的截取错处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover()关键字),会导致该goroutine所属的进程打印异常信息后直接退出。
defer func(){ if r := recover(); r !=nil { log.Printf("Runtime error caught: %v", r) } }()