断言
- 格式: 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】", "条件不成立", "不检查")
}
}
}
}