Golang错误与异常

面向对象编程

  • OOP思想 :拟人化思想。物以类聚. 类:抽象的模板,定义一个类(属性、方法),实例化出来一个对象-具体的。

  • OOP三大特性:封装、继承、多态

  • Go语言不是面向对象的编程语言,有一些机制可以实现面向对象编程的思维

  • 封装:结构体封装 + 方法实现 , 模拟一个类

  • 继承:匿名字段 、提升字段 (属性、方法)

  • 多态:一个事务可以拥有多种形态(接口)

  • 空接口 any

接口嵌套

package main
​
import (
   "fmt"
)
​
type AA interface {
   test1()
}
type BB interface {
   test2()
}
​
// 接口嵌套  CC :  test1()/test2()/test3()
// 如果要实现接口CC,那么需要实现这个三个方法。那这个对象就有3个接口可以转型。
type CC interface {
   AA // 导入AA接口中的方法
   BB
   test3()
}
​
// 编写一个结构体实现接口CC
type Dog7 struct {
}
​
func (dog Dog7) test1() {
   fmt.Println("test1")
}
func (dog Dog7) test2() {
   fmt.Println("test2")
}
func (dog Dog7) test3() {
   fmt.Println("test3")
}
​
func main() {
   // dog 拥有4种形态: Dog7 、CC 、 BB 、 AA
   var dog Dog7 = Dog7{}
   dog.test1()
   dog.test2()
   dog.test3()
​
   // 
   var a AA = dog
   a.test1()
   //a.test2() // 向上转型之后只能调用它自己对应的方法
   var b BB = dog
   b.test2()
   var c CC = dog
   c.test1()
   c.test2()
   c.test3()
}

接口断言

检查一个接口类型的变量是不是符合你的预期值。

比如:我们预期使用 test3() . 如果传递的是 a 、b 对象,我们就需要判断这个对象是否是我们预期的对象。 = 断言。

被断言的对象必须是接口类型,否则会报错

如果一个对象存在多种形态: 接口判断 登录 20个实现类 微信登录

  • i.(T) 判断是否是预期接口

  • swtich i.(type) 判断是否是预期的case结果

package main
​
import "fmt"
​
// 通过switch来判断  switch i.(T)
​
type I interface{}
​
// 如果断言的类型同时实现了switch 多个case匹配,默认使用第一个case
func testAsserts(i interface{}) {
   // switch i.(type) 接口断言
   switch i.(type) {
​
   case string:
      fmt.Println("变量为string类型")
   case int:
      fmt.Println("变量为int类型")
   case I:
      fmt.Println("变量为I类型")
   case nil:
      fmt.Println("变量为nil类型")
   case interface{}:
      fmt.Println("变量为interface{}类型")
​
   // .....
   default:
      fmt.Println("未知类型")
   }
}
​
func main() {
​
   testAsserts("string")
   testAsserts(1)
   var i I      // 默认值为 nil
   var i2 I = 1 // 只有赋值了之后,才是对应的类型
​
   testAsserts(i)
   testAsserts(i2)
   
}

type 别名

  • type xxx TTT 自定义类型

  • type xxx = TTT 起别名

package main
​
import "fmt"
​
// var 变量   type 类型(结构体、接口、别名...)
​
// type的别名用法,全局变量中
// 这是定义了一个新类型 MyInt,是int转换过来的,和int一样,但是不能通int发生操作,类型不同
// MyInt int
// 创建了一种新类型!
type MyInt int
​
func main() {
   var a MyInt = 20 // MyInt
   var b int = 10   // int
​
   // invalid operation: a + b (mismatched types MyInt and int)
   //fmt.Println(a + b)
   // 类型转换: T(v)
   fmt.Println(int(a) + b) // 30
   fmt.Printf("%T\n", a)   // main.MyInt
   fmt.Printf("%T\n", b)   // int
​
   // 给int起一个小名,但是它还得是int   type  any
​
   var c diyint = 30
​
   fmt.Printf("%T\n", c) // int
​
}
​
/*
type关键字的理解:
1、type 定义一个类型
 - type User struct 定义结构体类型
 - type User interface 定义接口类型
 - type Diy (int、string、....) 自定义类型,全新的类型
​
2、type 起别名
 - type xxx = 类型 ,将某个类型赋值给 xxx,相当于这个类型的别名
 - 别名只能在写代码的时候使用,增加代码的可阅读性。
 - 真实在项目的编译过程中,它还是原来的类型。
*/

异常和错误

错误与异常

错误:指的是程序中预期会发生的结果,预料之中

打开一个文件:文件正在被占用,可知的。

异常:不该出现问题的地方出现了问题,预料之外

调用一个对象,发现这个对象是个空指针对象,发生错误。

错误是业务的一部分,而异常不是。

go语言开发过程中遇到最多的代码,就是error。

需要将所有的错误情况都考虑到,并写到你的代码中。

错误 error

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

package main
​
import (
   "fmt"
   "os"
)
​
// 错误是开发中必须要思考的问题
// - 某些系统错误 ,文件被占用,网络有延迟
// - 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入
func main() {
​
   //打开一个文件 os 系统包,所有可以用鼠标和键盘能执行的事件,都可以用程序实现
   // func Open(name string) (*File, error)
   file, err := os.Open("aaa.txt")
   // 在开发中,我们需要思考这个错误的类型  PathError
   // 1、文件不存在 err
   // 2、文件被占用 err
   // 3、文件被损耗 err
   // 调用方法后,出现错误,需要解决
   if err != nil {
      fmt.Println(err)
      return
   }
​
   fmt.Println(file.Name())
}
​
// 在实际工程项目中,
// 我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
// Go语言没有提供像Java. c#语言中的try...catch异常处理方式,
// 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic
​
// 这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
// 好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。
​
// Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
// 错误值可以存储在变量中,从函数中返回,传递参数 等等。

自己定义一个错误

package main
​
import (
   "errors"
   "fmt"
)
​
// 自己定义一个错误
// 1、errors.New("xxxxx")
// 2、fmt.Errorf()  
// 都会返回  error 对象, 本身也是一个类型
func main() {
​
   age_err := setAge(-1)
   if age_err != nil {
      fmt.Println(age_err)
   }
   fmt.Printf("%T\n", age_err) // *errors.errorString
​
   // 方式二
   errInfo1 := fmt.Errorf("我是一个错误信息:%d\n", 500)
   //errInfo2 := fmt.Errorf("我是一个错误信息:%d\n", 404)
   if errInfo1 != nil {
      // 处理这个错误
      fmt.Println(errInfo1)
   }
​
}
​
// 设置年龄的函数,一定需要处理一些非正常用户的请求
// 返回值为 error 类型
// 作为一个开发需要不断思考的事情,代码的健壮性和安全性
func setAge(age int) error {
   if age < 0 {
      // 给出一个默认值
      age = 3
      // 抛出一个错误 errors 包
      return errors.New("年龄不合法")
   }
   // 程序正常的结果,给这个用户赋值
   fmt.Println("年龄设置成功:age=", age)
   return nil
}

自定义一个错误

package main
​
import (
   "fmt"
)
​
type KuangShenError struct {
   msg  string
   code int
}
// Error() string
func (e *KuangShenError) Error() string {
   //  fmt.Sprintf() 返回string
   return fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}
​
​
// 处理error的逻辑
func (e KuangShenError) print() bool {
   fmt.Println("hello,world")
   return true
}
​
​
​
// 使用错误测试
func test(i int) (int, error) {
   // 需要编写的错误
   if i != 0 {
      // 更多的时候我们会使用自定义类型的错误
      return i, &KuangShenError{msg: "非预期数据", code: 500}
   }
   // 正常结果
   return i, nil
}
​
func main() {
​
   i, err := test(1)
​
   if err != nil {
      fmt.Println(err)
      ks_err, ok := err.(*KuangShenError)
      if ok {
         if ks_err.print() {
            // 处理这个错误中的子错误的逻辑
         }
         fmt.Println(ks_err.msg)
         fmt.Println(ks_err.code)
      }
   }
​
   fmt.Println(i)
​
}

购物

下单:

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)

作业

自定义三个错误

1、简单的错误类型;只包含一些属性 、msg code

思路:
​
创建一个错误类型结构体
实现error接口
编写一个测试函数,返回err和正常值    func test(xxx ) (xx,err){}
在程序中调用这个错误,接收这个错误的结果
断言这个错误,解决错误

2、定义一个复杂的错误类型,包含属性和方法,msg code info 、检查这个错误是否符合预期、系统错误、认为错误

3、定义个统一返回结果:R (属性:msg、code,data) 方法:R.ok() R.error() R.info() (100%项目中都会有这个)

type R struct{

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值