Go语言中的错误处理及资源管理

2023-05-26 0 370

consequences

接下去如是说Go词汇中的consequences,这是两个开发人员最基本上的工夫。

defer延后句子

在如是说defer延后句子以后,他们先上看几段比较简单的代码:

package main import “fmt” func trydefer(){ fmt.Println(“1”) fmt.Println(“2”) fmt.Println(“3”) } func main(){ trydefer() }//运转结论: 1 2 3

那时他们将输入“1”的句子修正为defer fmt.Println(“1”),辨认出输入结论为2 3 1;接著在将输入“2”的句子修正为defer fmt.Println(“2”),再上看一看输入结论3 2 1;假如全数后面都加进defer呢?猜呵呵输入结论:3 2 1。

因而他们晓得defer延后句子保证初始化在表达式完结时出现,换句话说表达式运转到defer句子处会埃唐佩县现阶段句子,等该表达式继续执行完后,依照科天料的次序继续执行defer句子。

延后句子被用作继续执行两个表达式初始化,在那个表达式以后,延后句子回到。模块在defer句子时排序,defer条目为科天料或是是后进先出。

defer句子遇到panic,return,error等情形也能恒定继续执行:

func trydefer(){ defer fmt.Println(“1”) defer fmt.Println(“2”) fmt.Println(“3”) return fmt.Println(“4”) //那个代码不会继续执行,因为已经return了 } func main() { trydefer() } //运转结论: 3 2 1

再上看呵呵panic:

func trydefer(){ defer fmt.Println(“1”) defer fmt.Println(“2”) fmt.Println(“3”) panic(“程序运转到这里肯定会出错”) fmt.Println(“4”) } func main() { trydefer() } //运转结论: 3 2 1 panic: 程序运转到这里肯定会出错

但是一般都是在写文件的时候才会采用defer防止自己忘记关闭连接,关闭文件,释放资源等。新建两个fib文件,接著在里面新建两个fib.go文件,里面写入闭包实现输入斐波那契数列的表达式:

package fib //闭包 func Fptest()func()int{ a, b:=0,1 return func() int { a,b = b,a+b return a } }

然后回到main包下的main.go文件,里面写入以下代码:

package main import ( “bufio” “fib” “fmt” “os” ) func Writefile(filename string){ file ,err := os.Create(filename)if err!=nil{ panic(err) } defer file.Close() //关闭文件 //这样写的话文件速度较慢,可以先写到内存中,然后一次性写入文件中,下面就是那个代码 writer:=bufio.NewWriter(file) defer writer.Flush() //记得将数据从内存推入文件中,否则输入的数据仅仅在内存中 f:= fib.Fptest() for i:=0;i<5;i++{ fmt.Fprintln(writer,f()) } } func main(){ Writefile(“fib.txt”) }

运转该文件后,辨认出”fib.txt”文件中已经写入1 1 2 3 5了。

consequences

人工处理

后面他们都是使用panic来输入错误error,但是并没有处理错误,下面他们就来尝试处理呵呵错误。在上面写文件的时候,他们使用了os.Create(filename)那个方法,查看呵呵它的源码:

// Create creates the named file with mode 0666 (before umask), truncating // it if it already exists. If successful, methods on the returned // File can be used for I/O; the associated file descriptor has mode // O_RDWR. // If there is an error, it will be of type *PathError. func Create(name string) (*File, error) { returnOpenFile(name, O_RDWR|O_CREATE|O_TRUNC,0666) }

看到没它其实是会回到很多信息的,他们尝试修正呵呵以后的代码,将file ,err := os.Create(filename)这句修正为file ,err := os.OpenFile(filename,os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666)。然后运转呵呵,会辨认出出了问题,报以下错误:

panic: open fib.txt: The file exists.

既然晓得会报错,因而可以不再输入panic(err),而是使用下面这种形式的代码,这样程序可以恒定继续执行,而不会因为错误而停止运转:

if err!=nil{ fmt.Println(“The file exists.”) return }

这样其实前提是已经晓得出现了什么错误,假如不晓得可以直接查看error本身的源码,辨认出它是两个接口:

// The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface { Error() string }

既然是接口,那就可以直接拿来使用了,直接输入fmt.Println(“err:”,err.Error()),再次运转呵呵辨认出结论真的输入了错误:err: open fib.txt: The file exists.。

那个代码其实是呵呵子全数把错误信息输出来了,后面在看Create方法源码的时候,你是否注意到了一点:If there is an error, it will be of type *PathError.假如出现两个错误,那它将会是*PathError,也就是多种PathError类型。使用后面如是说的动态类型检查错误的具体类型,然后再一次修正consequences的代码:

if err !=nil{ ifpathError,ok :=err.(*os.PathError);!ok{panic(err) }else{ fmt.Printf(“%s,%s,%s\n”,pathError.Op,pathError.Path,pathError.Err)//op是操作,path是路径,err是错误 } } //运转结论: open,fib.txt,The file exists.

当然你还可以自己定义error,使用如下方法:err=errors.New(“这是自定义的error”),然后程序运转就会触发panic,进而导致程序崩溃,因为自己定义的error不是os.PathError类型。

简单总结呵呵错误类型的表示,它是两个接口,因而任何实现该接口的类型都可以作为两个错误,进而初始化该方法实现对错误的描述。

type error interface { Error() string }

统一consequences

那时又这么两个场景,100台服务器同时出现了某个错误,那么他们应该怎样编写高可复用的代码呢?往下看你就晓得了。

error和panic区别 : 意料之中用error,如文件打不开;意料之外用panic,如数组越界。

一般在下列情形使用defer:Open/Close;Lock/Unlock;PrintHeader/PrintFooter等情形。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务