day09 断言 + 错误 + Type自定类型

断言

  • 格式: t,ok:=i.(T) 【t:就是i接口是T类型的,i:接口,T:类型】
// 断言失败不希望程序停止
func assertInt(i any) {
	i, ok := i.(int)
	fmt.Println(i, ok)
	if ok {
		fmt.Println("int类型")
	} else {
		fmt.Println("非int类型")
	}
}

switch 实现断言不中断

package main

import "fmt"

type MyType struct{}

func assertDifferentType(i any) {
	// i.(type) :必须使用 switch 。  否则异常:Usage of .(type) is outside of the type switch
	switch i.(type) {
	case MyType:
		fmt.Println("MyType")
	case int:
		fmt.Println("int")
	case float64:
		fmt.Println("float64")
	case string:
		fmt.Println("string")
	case interface{}:
		fmt.Println("empty interface")

	case nil:
		fmt.Println("nil")
	default:
		fmt.Println("未知类型")
	}
}

func main() {
	/*
		switch case default 能够实现 不同类型判断
	*/
	assertDifferentType("1")
	assertDifferentType(1)
	assertDifferentType(1.2)

	// MyType类型
	var nilVariable MyType // {}
	assertDifferentType(nilVariable)

	// nil类型
	var emptyInterface interface{}      // nil
	assertDifferentType(emptyInterface) // nil

	var mt = MyType{}
	fmt.Println(mt)         // {}
	assertDifferentType(mt) // MyType

}

Type 关键字,自定义新类型

  • 定义结构体 : type xxx struct{}
  • 定义接口 : type xx interface{}
  • 自定义类型。 newType : type newInt int 。 【newInt 和 int 属于两种类型。不同类型不能计算 】
  • 给 某个已有类型 起别名 : type anotherNameType = int 【anotherNameType 还是 int 类型】
package main

import "fmt"

// type 定义新类型
type myType2 int

func main() {
	/*
		type 关键字:
			- 定义结构体 : type xxx struct{}
			- 定义接口	: type xx interface{}
			- 自定义类型。 newType : type newInt int 。 【newInt 和 int 属于两种类型。不同类型不能计算 】
			- 给 某个已有类型 起别名	: type anotherNameType = int  【anotherNameType 还是 int 类型】
	*/

	var i int = 1
	fmt.Println("i=", i)

	// 使用新类型
	var i2 myType2 = 1
	fmt.Printf("i2 【值】:%v,【类型】%T\n", i2, i2) //i2 【值】:1,【类型】main.myType2
	fmt.Println("i 是 int 类型。 i2 是 main.myType2。 虽然main.myType2继承于int。但是 i 和 i2 不能做同类型计算")

	// 使用 type 新别名
	type myType3 = int
	var i3 myType3 = 100
	fmt.Printf("i3 【值】:%v,【类型】%T\n", i3, i3) // i3 【值】:100,【类型】int
	fmt.Println("i 是 int 类型。 i3 是 int。 i 和 i3 是同类型,可以计算")

}

异常和错误的区别

  • 错误: 预期内的错误
  • 异常: 未知的问题
package main

import (
	"fmt"
	"os"
)

func main() {
	/*
		- 错误 和 异常
			-错误: 预期内的错误
			- 异常:	未知的问题
	*/

	// 错误 error: 例如: sql注入,网络延迟,文件占用。 必须及时处理错误,否则程序抛出错误
	// PathError 是一个结构体
	// 问题1: 文件不存在
	// 问题2: 文件被占用
	// 问题3:文件损坏
	file1, err1 := os.Open("golang_base_17/day09接口和错误/data.txt") // Open(name string) (*File, error)
	fmt.Println("文件:data.txt", file1.Name(), err1)

	file2, err2 := os.Open("golang_base_17/day09接口和错误/data1.txt") // Open(name string) (*File, error)
	if err2 != nil {
		fmt.Println("解决错误::", err2) // 解决错误:: open data1.txt: no such file or directory
	} else {
		fmt.Println("文件:data1.txt", file2.Name(), err1)
	}

	// 小结:可以将异常处理分成两种: 1 要处理的err,当error 多了后,可以以函数的形式处理错误, 2 _ 匿名接收所有错误不处理

}

错误包errors的使用

  • 错误errors三种使用方式
  • errors.New("") 定义简单字符串错误
  • fmt.Errorf("") 格式化输出错误
  • 使用断言 t.(*T类型) 输出错误信息
package main

import (
	"errors"
	"fmt"
	"net"
)

func main() {
	/*
		- 错误errors三种使用方式
			- errors.New("") 定义简单字符串错误
			- fmt.Errorf("") 格式化输出错误
			- 使用断言 t.(*T类型) 输出错误信息
	*/
	age := -100
	// 方式一:自定义检查函数。通过errors模块返回错误信息 New 创建一个错误信息
	ageErr := checkAge(age)
	fmt.Printf("%T\n", ageErr) // *errors.errorString
	fmt.Printf("%v\n", ageErr) // 年龄小于0

	// 方式二: fmt.Errorf . fmt 工具包提供了错误处理格式函数
	fmtErr01 := fmt.Errorf("网络错误信息:%d\n", 500)
	fmtErr02 := fmt.Errorf("参数误信息:%d", 400)
	fmt.Printf("%T\n", fmtErr01) // *errors.errorString
	fmt.Printf("%v\n", fmtErr01) // 网络错误信息:500
	if fmtErr02 != nil {
		fmt.Printf("fmtErr02:%T\n", fmtErr02) //fmtErr02:*errors.errorString
		fmt.Printf("fmtErr02:%v\n", fmtErr02) // fmtErr02:参数误信息:400
	}

	// 方式三: 断言检查错误 t.(*T)
	// net 是一个网络包
	address, err := net.LookupHost("www.baidu122.com")
	fmt.Println(address, err)
	netErr, ok := err.(*net.DNSError)
	fmt.Printf("netErr 断言结果的错误类型:%T\n", netErr) // *net.DNSError
	fmt.Printf("ok 断言结果的错误类型:%T\n", ok)         // bool
	if ok {
		if netErr.Temporary() {
			fmt.Println("临时错误...")
		} else if netErr.Timeout() {
			fmt.Println("网络超时错误...")
		} else {
			fmt.Println("未知错误...")
		}
	}
}

func checkAge(age int) error {
	// error 实现 error interface 接口函数
	if age < 0 {
		return errors.New("年龄小于0")
	} else if age > 100 {
		return errors.New("年龄大于100")

	} else {
		fmt.Println("年龄正常:", age)
	}
	return nil
}

自定义错误

  • 自定义错误结构体
  • 实现自定结构体的Error()错误方法
  • 编写函数处理业务逻辑,并且包含自定义错误处理
package main

import "fmt"

// 1. 自定义错误结构体
type MyHttpStructError struct {
	statusCode int
	message    string
	data       interface{}
}

// 2. 实现自定结构体的Error()错误方法
func (mys MyHttpStructError) Error() string {
	// fmt.Sprintf() : 根据格式说明符进行格式化并返回结果字符串。
	return fmt.Sprintf("【MyHttpStruct 错误】。状态码:%d,错误信息:%s,数据:%v", mys.statusCode, mys.message, mys.data)
}
func (mys MyHttpStructError) pprint() bool {
	switch mys.statusCode {
	case 400:
		return true
	case 403:
		return true
	case 500:
		return true
	case 600:
		return false
	default:
		return false
	}
}

// 3. 编写函数处理业务逻辑,并且包含自定义错误处理
func myView(code int) (string, error) {
	if code == 600 {
		return "访问失败", &MyHttpStructError{statusCode: 600, message: "未知错误"}
	}
	return "访问成功", nil
}

func main() {
	/* 自定义错误 */

	// 调用自定义错误
	res, err := myView(600)
	fmt.Println("【基础错误信息】:", res, err)
	if err != nil {
		myErrFunc, ok := err.(*MyHttpStructError)
		if ok {
			fmt.Println(myErrFunc.pprint())
			if !myErrFunc.pprint() {
				fmt.Println("【自定义错误:pprint】", "条件成立", "执行 pprint 函数检查后的错误逻辑")
			} else {
				fmt.Println("【自定义错误:pprint】", "条件不成立", "不检查")
			}
		}
	}

}

posted @ 2024-07-02 07:49  染指未来  阅读(2)  评论(0编辑  收藏  举报