Go错误与异常

面向对象编程

  • 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)

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值