互联网站备案,网络营销的定义和内容,关键词排名优化易下拉效率,深圳最好用的网站设计✨✨ 欢迎大家来到景天科技苑✨✨
#x1f388;#x1f388; 养成好习惯#xff0c;先赞后看哦~#x1f388;#x1f388; #x1f3c6; 作者简介#xff1a;景天科技苑 #x1f3c6;《头衔》#xff1a;大厂架构师#xff0c;华为云开发者社区专家博主#xff0c;…
✨✨ 欢迎大家来到景天科技苑✨✨ 养成好习惯先赞后看哦~ 作者简介景天科技苑 《头衔》大厂架构师华为云开发者社区专家博主阿里云开发者社区专家博主CSDN全栈领域优质创作者掘金优秀博主51CTO博客专家等。 《博客》Python全栈Golang开发PyQt5和Tkinter桌面开发小程序开发人工智能js逆向App逆向网络系统安全数据分析Djangofastapiflask等框架云原生K8Slinuxshell脚本等实操经验网站搭建数据库等分享。 所属的专栏Go语言开发零基础到高阶实战 景天的主页景天科技苑 文章目录 Go语言中的错误与异常1. Go语言错误 error1自定义错误1. 使用errors.New()2.使用fmt.Errorf()3. 综合案例 2自定义错误类型难点1、定义一个结构体2、为该结构体创建个方法实现go内置error接口中的Error方法3、创建个方法测试4、main方法中写逻辑 2. Go语言的异常处理机制1使用panic2使用recover1. recover案例展示2. recover结合多个defer执行顺序 Go语言中的错误与异常
在Go语言编程中错误和异常处理是非常重要的一部分。Go语言通过其独特的错误处理机制和异常处理模型提供了一种既清晰又高效的方式来处理程序运行时的错误和异常情况。
错误指的是程序中预期会发生的结果预料之中
打开一个文件文件正在被占用可知的。
异常不该出现问题的地方出现了问题预料之外
调用一个对象发现这个对象是个空指针对象发生错误。
错误是业务的一部分而异常不是。
go语言开发过程中遇到最多的代码就是error。
需要将所有的错误情况都考虑到并写到你的代码中。
1. Go语言错误 error
鼓励工程师在代码中显式的检查错误而非忽略错误。
错误是开发中必须要思考的问题
某些系统错误 文件被占用网络有延迟人为错误核心就是一些不正常的用户会怎么来给你传递参数sql注入
在实际工程项目中 我们希望通过程序的错误信息快速定位问题但是又不喜欢错误处理代码写的冗余而又啰嗦。 Go语言没有提供像Java. c#语言中的try…catch异常处理方式 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误程序就终止 panic
这种设计,鼓励工程师在代码中显式的检查错误而非忽略错误。 好处就是避免漏掉本应处理的错误。但是带来一个弊端让代码繁琐。
Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的如int, float64。 错误值可以存储在变量中从函数中返回传递参数 等等。
代码示例
package mainimport (fmtos
)// 错误是开发中必须要思考的问题
// - 某些系统错误 文件被占用网络有延迟
// - 人为错误核心就是一些不正常的用户会怎么来给你传递参数sql注入
func main() {//工作目录是指在执行程序时操作系统认为当前正在工作的目录。//一般情况下我们通过在终端或文件浏览器中打开文件时所处的目录就是当前工作目录。//os.Getwd()只能获取当前项目的工作目录并不是当前文件所在路径path, _ : os.Getwd()fmt.Println(Path:, path)err : os.Chdir(F:\\goworks\\src\\jingtian\\yufa\\错误与异常)if err ! nil {return}//再次查看路径path2, _ : os.Getwd()fmt.Println(再次查看Path:, path2)//打开一个文件 os 系统包所有可以用鼠标和键盘能执行的事件都可以用程序实现//os.Open()返回 一个文件对象和错误error// func Open(name string) (*File, error)file, err2 : os.Open(aaa.txt)// 在开发中我们需要思考这个错误的类型 PathError// 1、文件不存在 err// 2、文件被占用 err// 3、文件被损耗 err// 调用方法后出现错误需要解决if err2 ! nil {fmt.Println(err2)return}fmt.Println(file.Name())
}// 在实际工程项目中
// 我们希望通过程序的错误信息快速定位问题但是又不喜欢错误处理代码写的冗余而又啰嗦。
// Go语言没有提供像Java. c#语言中的try...catch异常处理方式
// 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误程序就终止 panic// 这种设计,鼓励工程师在代码中显式的检查错误而非忽略错误。
// 好处就是避免漏掉本应处理的错误。但是带来一个弊端让代码繁琐。// Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的如int, float64。
// 错误值可以存储在变量中从函数中返回传递参数 等等。如果文件不存在运行就会捕获错误
文件存在就可以正常打印文件名称
1自定义错误
1. 使用errors.New()
errors.New()函数是最简单的创建错误的方式。它接受一个字符串作为参数并返回一个实现了error接口的错误值。 返回值的类型为 *errors.errorString可以使用Error()方法将err转化为字符串 看下源码
package mainimport (errorsfmt
)func main() {err : errors.New(这是一个错误)if err ! nil {fmt.Println(err)fmt.Printf(错误类型%T\n, err)//可以使用Error()方法将err转化为字符串// 注意如果err为空调用Error()方法会报错所以该方法一定要在if err ! nil条件中执行fmt.Printf(错误类型%T\n, err.Error())}
}2.使用fmt.Errorf()
fmt.Errorf()函数比errors.New()更灵活它允许你使用格式化字符串来创建错误。这对于需要动态构建错误信息的场景非常有用。
package mainimport (fmt
)func main() {err : fmt.Errorf(错误代码: %d, 错误信息: %s, 1001, 操作失败)if err ! nil {fmt.Println(err.Error())}
}3. 综合案例
package mainimport (errorsfmt
)// 自己定义一个错误
// 1、errors.New(xxxxx)
// 2、fmt.Errorf()
// 都会返回 error 对象 本身也是一个类型func main() {//根据用户传参数据用我们定义好的函数处理age_err : setAge(-3)if age_err ! nil {fmt.Println(age_err)}fmt.Printf(%T\n, age_err) // *errors.errorString//如果age_err为空调用Error()方法会报错fmt.Printf(%T\n, age_err.Error()) // string// 方式二errInfo1 : fmt.Errorf(我是一个错误信息%d\n, 500)//errInfo2 : fmt.Errorf(我是一个错误信息%d\n, 404)if errInfo1 ! nil {// 处理这个错误fmt.Println(errInfo1)fmt.Printf(%T\n, errInfo1.Error())}}// 设置年龄的函数一定需要处理一些非正常用户的请求
// 返回值为 error 类型 这个是内置类型
// 作为一个开发需要不断思考的事情代码的健壮性和安全性
func setAge(age int) error {if age 0 {// 给出一个默认值age 3// 抛出一个错误 errors 包return errors.New(年龄不合法)}// 程序正常的结果给这个用户赋值fmt.Println(年龄设置成功age, age)//年龄合法就返回nilreturn nil
}2自定义错误类型难点
虽然errors.New()和fmt.Errorf()很方便但在某些情况下你可能需要更丰富的错误信息。这时可以通过自定义类型来实现go内置的error接口。 自定义错误类型步骤
1、定义一个结构体
// JingTian 定义一个结构体
type JingTian struct {msg stringcode int
}2、为该结构体创建个方法实现go内置error接口中的Error方法
内置接口
// 注意Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意方法的调用者用指针类型因为结构体是值类型不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {// fmt.Sprintf() 返回stringreturn fmt.Sprintf(错误信息%s,错误代码%d\n, e.msg, e.code)
}3、创建个方法测试
// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i ! 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息不常用信息太少了// 更多的时候我们会使用自定义类型的错误//注意返回的错误用内存地址因为结构体是值类型return i, JingTian{msg: 非预期数据, code: 500}}// 正常结果return i, nil
}4、main方法中写逻辑
func main() {i, err : test(1)if err ! nil {fmt.Println(err)//查看错误类型fmt.Printf(%T\n, err)ks_err, ok : err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}完整代码
package mainimport (fmt
)// JingTian 定义一个结构体
type JingTian struct {msg stringcode int
}// 注意Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意方法的调用者用指针类型因为结构体是值类型不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {// fmt.Sprintf() 返回stringreturn fmt.Sprintf(错误信息%s,错误代码%d\n, e.msg, e.code)
}// 自定义错误里面还可以写一些方法
// 处理error的逻辑
func (e *JingTian) print() bool {fmt.Println(helloworld)return true
}// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i ! 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息不常用信息太少了// 更多的时候我们会使用自定义类型的错误//注意返回的错误用内存地址因为结构体是值类型return i, JingTian{msg: 非预期数据, code: 500}}// 正常结果return i, nil
}func main() {i, err : test(1)if err ! nil {fmt.Println(err)//查看错误类型fmt.Printf(%T\n, err)ks_err, ok : err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}go语言中业务逻辑其实代码量并不大大多数是在处理错误逻辑 比如下购物商城代码 购物
下单
1、查询商品信息 FindGoodsError msg、code | fun-商品不在了 fun-商品失效 fun-网络错误
2、查询库存 FindxxxError msg、code | fun-库存为0 fun-库存0
3、查询物流是否可以到达 xxxError msg、code | fun fun
4、查询价格生成订单 xxxError msg、code | fun fun
5、支付成功与否 xxxError msg、code | fun fun
6、成功就产生一个订单推送到商家和物流 xxxError msg、code | fun fun
2. Go语言的异常处理机制
panic 和 recover 与错误处理不同Go语言中的异常处理是通过panic和recover关键字来实现的。panic用于表示程序中的严重错误它会导致程序中断执行recover用于捕获panic并恢复程序的正常执行流程。
1使用panic
什么时候会发生恐慌panic我们不知道什么时候会报错 程序运行的时候会发生panic 手动抛出panic。我们在一些能够预知到危险的情况下可以主动抛出 panic可以接受任何类型的值作为参数通常是一个字符串或错误对象用于描述发生的异常。 使用 panic() 程序就会终止,停在这里强制结束
看下源码
package mainimport fmtfunc main() {panic(发生了异常)//panic后面的代码程序不会执行fmt.Println(hello world)
}在上面的例子中程序会在执行到panic时中断并打印出发生了异常这条消息。
如果有panic发生我们尽可能接收它并处理 出现了panic之后如果panic语句前面有defer语句先执行所有的defer语句。panic语句后面的defer语句不再执行
package mainimport fmt// panic recover
//
// 出现了panic之后如果panic语句前面有defer语句先执行所有的defer语句。
//
// defer : 延迟函数倒序执行处理一些问题。
func main() {defer fmt.Println(main--1)defer fmt.Println(main--2)fmt.Println(main--3)testPanic(1) // 外部函数执行完panic之前的所有defer//后面的都不执行了defer fmt.Println(main--4)fmt.Println(main--5)
}
func testPanic(num int) {defer fmt.Println(testPanic--1)defer fmt.Println(testPanic--2)fmt.Println(testPanic--3)// 如果在函数中一旦触发了 panic会终止后面要执行的代码。// 如果panic语句前面存在defer正常按照defer逻辑执行。panic语句后面的defer语句不再执行if num 1 {panic(出现预定的异常----panic)}defer fmt.Println(testPanic--4)fmt.Println(testPanic--5)
}2使用recover
go 语言是追求简洁的他没有使用 try…catch 语句 如果有些情况必须要处理异常就需要使用panic抛出了异常recover接收这个异常来处理。 recover结合defer处理 panic 恐慌 recover必须在defer语句中调用才能捕获到panic。defer语句会延迟函数的执行直到包含它的函数即将返回时才执行defer语句中的函数。 一般我们在某个函数抛出的panic就在那个函数里面解决了 recover会返回panic的参数
recover返回任意类型
1. recover案例展示
package mainimport (fmt
)func main() {//defer语句绑定的匿名函数defer func() {r : recover()if r ! nil {fmt.Println(捕获到异常:, r)}}()panic(发生了异常)fmt.Println(这行代码不会被执行)
}在这个例子中尽管在defer之后有panic调用但defer中的函数仍然会执行并捕获到panic抛出的异常。然后程序会跳过panic之后的代码继续执行defer之后的逻辑。
2. recover结合多个defer执行顺序
package mainimport fmt// panic recover
//
// 出现了panic之后如果有defer语句先执行所有的defer语句。
//
// defer : 延迟函数倒序执行处理一些问题。
func main() {defer fmt.Println(main--1)defer fmt.Println(main--2)fmt.Println(main--3)testPanic2(1) // 外部函数如果在函数内部已经处理panic,那么程序会继续执行defer fmt.Println(main--4)fmt.Println(main--5)
}
func testPanic2(num int) {// 出去函数的时候处理这里面可能发生的panic// recover func recover() any 返回panic传递的值// panic func panic(v any)defer func() {if msg : recover(); msg ! nil {fmt.Println(recover执行了... panic msg:, msg)// 处理逻辑fmt.Println(---------程序已恢复----------)}}()defer fmt.Println(testPanic--1)defer fmt.Println(testPanic--2)fmt.Println(testPanic--3)// 如果在函数中一旦触发了 panic会终止后面要执行的代码。// 如果存在defer正常按照defer逻辑执行if num 1 {panic(出现预定的异常----panic)}defer fmt.Println(testPanic--4)fmt.Println(testPanic--5)
}执行逻辑
1、panic 触发
2、触发panic当前函数panic前面的所有defer语句倒序执行
3、直到遇到recover处理了这个panic…函数结束
4、main继续向下执行。