首页 > 其他分享 >狂神说Go语言—错误与异常

狂神说Go语言—错误与异常

时间:2022-12-29 12:22:40浏览次数:35  
标签:defer 错误 -- fmt Println test Go 狂神 main

什么是错误error

什么是错误

错误指的是可能出现问题的地方出现了问题。比如打开一个文件时失败,这种情况在人们的意料之中。
和错误类似的还有一个异常,指的是不应该出现问题的地方出现了问题。比如引用了空指针,这种情况在人们的意料之外。可见,错误是业务过程的一部分,而异常不是。

打开文件,存在错误情况

package main

import (
   "fmt"
   "os"
)

func main() {
   // 打开一个文件
   file, err := os.Open("abc.txt")
   if err != nil { //当有错误时,打印输出并返回
      fmt.Println(err)
      return
   } else { //否则打开文件
      fmt.Println(file)
   }
}
/*
open abc.txt: The system cannot find the file specified.
*/

在实际工程项目中,我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。

Go语言没有提供像Java.c#语言中的try..catch异常处理方式,而是通过函数返回值逐层往上抛。

这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误

好处就是避兔漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。

Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。错误值可以存储在变量中,从函数中返回,等等。

创建自己的errp错误信息

//创建一个自己的error错误信息,通过errors可以创建
1、errors.New("我是一个错误信息")

//也可以通过fmt创建
2、fmt.Errorf("我是一个错误信息%T", 500)
package main

import (
   "errors"
   "fmt"
)

func main() {
   // 通过errors创建
   errinfo := errors.New("我是一个错误信息")
   fmt.Printf("%T\n", errinfo) //打印输出类型

   err := setage(-1)
   if err != nil {
      fmt.Println(err)
   }

   // 还可以通过fmt创建
   errinfo2 := fmt.Errorf("我是一个错误信息%T", 500)
   fmt.Printf("%T\n", errinfo2) //打印输出类型

}

// 定义一个setage函数
func setage(age int) error {
   if age < 0 {
      return errors.New("年龄输入不合法")
   } else {
      fmt.Println(age)
      return nil
   }
}
/*
*errors.errorString
年龄输入不合法
*errors.errorString
*/

错误类型

error类型是一个接口类型

type error interface{
	Error()string
}

通过断言,来判断具体的错误类型,然后进行对应的错误处理

package main

import (
	"fmt"
	"os"
)

func main() {
	//	打开一个文件
	file, err := os.Open("abc.txt")
	if err != nil { //当有错误时,打印输出并返回
		fmt.Println(err)
		temp, ok := err.(*os.PathError)
		if ok {
			fmt.Println(temp.Op)
			fmt.Println(temp.Err)
			fmt.Println(temp.Path)
		}
        /*
		open
		The system cannot find the file specified.
		abc.txt
		*/
		return
	} else { //否则打开文件
		fmt.Println(file)
	}
}
package main

import (
   "fmt"
   "net"
)

func main() {

   addrs, err := net.LookupHost("www.baidu.com")
   fmt.Println(err)
   dnsError, ok := err.(*net.DNSError)
   if ok {
      if dnsError.Timeout() {
         fmt.Println("超时")
      } else if dnsError.Temporary() {
         fmt.Println("临时错误")
      } else {
         fmt.Println("其他错误")
      }
   }
   fmt.Println(addrs)
}
/*
<nil>
[14.215.177.38 14.215.177.39]
*/

自定义错误类型

package main

import "fmt"

// 自定义一个错误结构体
type Mydiyerror struct {
   msg  string
   code int
}

// 实现方法接收 对象为Mydiyerror, 返回值类型为string
func (e Mydiyerror) Error() string {
   return fmt.Sprint("错误信息", e.msg, "状态码:", e.code)
}

func test04(i int) (int, error) {
   if i != 0 {
      return i, &Mydiyerror{"非零数据", 500}
   }
   return i, nil
}

func main() {
   i, err := test04(1)
   if err != nil {
      myerr, ok := err.(*Mydiyerror)
      if ok {
         fmt.Println(myerr.msg)
         fmt.Println(myerr.code)
      }
   }
   fmt.Println(i)
}
/*
非零数据
500
1
*/

panic和recover

go语言追求简洁,所以go语言中没有try...catch语句

因为go语言的作者认为将异常和控制语句混在一起,很容易让这个程序变得混乱,异常也很容易被滥用。

所以在go语言中,为了防止异常被滥用,我们常常使用函数的返回值来返回错误,而不是用异常来代替错误

如果在一些场景下确实需要处理异常,就可以使用panic和recover

panic用来抛出异常,recover用来恢复异常

panic

如果函数F中书写并触发了panic语句,会终止其后要执行的代码。在panic所在函数F内如果存在要执行的defer函数列表,则按照defer书写顺序的逆序执行

package main

import "fmt"

func main() {
   //2.执行顺序为main--3, test05方法中test 3  2  1,main 2 1
   defer fmt.Println("main--1")
   defer fmt.Println("main--2")
   fmt.Println("main--3")
   test05(1)
   fmt.Println("main--4")
   defer fmt.Println("main--5")
}
func test05(num int) {
   //1.执行顺序分别是3  2 1  在panic后面的4和5不执行
   defer fmt.Println("test--1")
   defer fmt.Println("test--2")
   fmt.Println("test--3")
   if num == 1 {
      panic("出现异常——————")
   }
   fmt.Println("test--4")
   defer fmt.Println("test--5")
}
/*
main--3
test--3
test--2
test--1
main--2
main--1
panic: 出现异常——————
*/

recover

recover的作用是捕获panic,从而恢复正常代码执行

recover必须配合defer使用

recover没有传入的参数,但是有返回值,返回值就是panic传递的值

package main

import "fmt"

func main() {
   
   defer fmt.Println("main--1")
   defer fmt.Println("main--2")
   fmt.Println("main--3")
   test05(1)
   fmt.Println("main--4")
   defer fmt.Println("main--5")
}
func test05(num int) {
   
   defer func() {
      msg := recover()
      if msg != nil {
         fmt.Println("程序恢复了————")
      }
   }()

   defer fmt.Println("test--1")
   defer fmt.Println("test--2")
   fmt.Println("test--3")
   if num == 1 {
      panic("出现异常——————")
   }
   fmt.Println("test--4")
   defer fmt.Println("test--5")
}
/*
main--3
test--3
test--2
test--1
程序恢复了————
main--4
main--5
main--2
main--1
*/
  • 触发panic
  • 逆序执行test05函数中的panic前三条的语句
  • 执行到第三条defer时,recover恢复恐慌并输出信息
  • 返回外部函数,程序继续执行

由于recover恢复恐惧,所以程序就不会panic而退出执行,外部函数还能够正常执行下去

标签:defer,错误,--,fmt,Println,test,Go,狂神,main
From: https://www.cnblogs.com/DuPengBG/p/17012201.html

相关文章

  • centos7下docker启动时报iptables错误
    centos7启动docker报错内容:iptablesfailed:iptables--wait-tnat-ADOCKER-ptcp-d0/0--dport22201-jDNAT--to-destination172.18.0.2:22!-idocker0:ip......
  • 记Flutter执行flutter doctor --android-licenses时出现错误
    错误描述今天刚刚安装好Flutter,执行了$flutterdoctor结果如图所示,出现一个Android令牌状态不可知的错误。根据提示信息,执行如下的命令,$flutterdoctor--android-......
  • 结合商业项目深入理解Go知识点
    这篇文章比较硬核,爆肝5千字,把之前整理的知识点都串起来了。建议先收藏,慢慢看。前言上一篇文章#【GoWEB进阶实战】开源的电商前后台API系统很受大家欢迎,有好多小伙伴......
  • uwsgj启动django服务 Djangoweb服务的部署采用 Nginx+uWSGI的方式
    1、SQLite3.8.3orlaterisrequired(found3.6.20).2、django.db.utils.Notsupportederror:urlsnotsupported3、nointernalroutingsupport,rebuildwithpcre......
  • vba-match和错误处理
    本文是讲match函数的踩坑点,大家注意避坑。1、MATCH函数只在一维数组或者二维一列数组中才有效。如图:A2为二维数组,A3为一维数组,A4为二维一列数组。B运算结果为Error20......
  • MongoDB - 副本集简介
    简介在MongoDB中,副本集指的是一组MongoDB服务器实例掌管同一个数据集,实例可以在不同的机器上。其中一个用于处理写操作的是主节点(Primary),还有多个用于保存主节点的数......
  • Django(2) - Django模板
    1.Django模板介绍基础概念模板是具有一定的格式或骨架,可以动态的生成HTML模板引擎决定以何种方式组织代码一个项目可以有一个或者是多个模板引擎,Django里面主要两个模......
  • argocd权限控制
    查看argocd当前存在的配置[root@k8s-master01test]#kubectlgetcm-nargocdNAMEDATAAGEargocd-cm2......
  • 90%的Java开发人员都会犯的5个错误
    前言作为一名java开发程序员,不知道大家有没有遇到过一些匪夷所思的bug。这些错误通常需要您几个小时才能解决。当你找到它们的时候,你可能会默默地骂自己是个傻瓜。是的,这......
  • 狂神说Go语言—面向对象编程讲解
    OOP思想Go语言不是面向对象语言,只是让大家理解一些面向对象的思想,通过一些方法来模拟面向对象语言的进化发展跟生物的进化发展是一回事,都是"物以类聚"语句多了,我们将完......