函数
4.1匿名函数,指没有名字符号的函数,除此之外,与普通函数相似
// 定义时调用。 _ = func(s string) string { return "[" + s + "]" }("abc")//abc立即作为参数被调用
func main() { wrap(func(s string) string { return "[" + s + "]" })() }//匿名函数作为传入变量
//你们函数作为结构体字段传递 func main() { calc := struct { add func(int, int) int mul func(int, int) int }{ add: func(x, y int) int { return x + y }, mul: func(x, y int) int { return x * y }, } _ = calc.add(1, 2) }
//匿名函数作为通道参数传递 func main() { fn := make(chan func()) go func() { defer close(fn) f := <- fn f() }() fn <- func(){ println("hi!") } <- fn }
闭包
是一个函数值,引用了其函数体之外的变量(闭包可以访问外部函数内的变量
-
保持状态:闭包可以用来创建具有状态的函数。函数内部的变量可以在多次调用之间保持其状态,而不需要全局变量。
保持状态: 闭包可以用于创建具有状态的函数。例如,您可以创建一个计数器函数,每次调用它都会增加计数值并返回。这种方式可以避免使用全局变量来维护状态。 go Copy code func createCounter() func() int { count := 0 return func() int { count++ return count } }
-
封装数据:闭包可以用于隐藏数据,只允许通过特定的函数来访问和修改数据。这有助于实现数据封装和隐藏细节。
-
回调函数:在异步编程中,闭包常常用作回调函数,以便在稍后的时间执行某些操作。
延迟调用
注册非nil函数,复制执行所有参数
多个延迟调用按FILO次序执行
执行时确保延迟调用总被执行(os.EXIT除外
延迟调用是函数结束时(所有)才被执行,不合理的使用方式会浪费很多资源
错误处理
标志性错误:一种明确状态,比如io.EOF
提示性错误:返回可读信息,提示错误原因
. errors.Unwrap
-
作用:
errors.Unwrap
函数用于获取被包装(wrapped)的错误。当你有一个错误,它是另一个错误的包装,errors.Unwrap
将返回被包装的那个错误。 -
使用场景:当你想要检查错误的底层原因时,你会使用
errors.Unwrap
。这通常发生在错误被多层包装的情况下。 -
示例代码:
var err error = fmt.Errorf("an error occurred: %w", io.ErrUnexpectedEOF) unwrappedErr := errors.Unwrap(err) if unwrappedErr == io.ErrUnexpectedEOF { // 处理特定的底层错误 }
2. errors.Is
-
作用:
errors.Is
函数用于判断一个错误是否等于或被包装在另一个错误中。它会递归地查看错误的整个链条,来判断是否存在特定的错误。 -
使用场景:在你只关心错误的类型或值,而不关心错误的具体内容时,
errors.Is
非常有用。它适用于检查错误是否为特定的已知类型或值。 -
示例代码:
var err error = fmt.Errorf("an error occurred: %w", io.ErrUnexpectedEOF) if errors.Is(err, io.ErrUnexpectedEOF) { // 处理特定的错误 }
3. errors.As
-
作用:
errors.As
函数用于将错误转换为特定的错误类型。如果错误链中的任何一个错误与提供的类型匹配,它会将错误的值赋给提供的类型变量。 -
使用场景:当你需要对错误进行更详细的检查或需要错误的具体数据时,使用
errors.As
。这在需要断言错误为特定类型时特别有用。 -
示例代码:
type MyError struct { Param int } func (m *MyError) Error() string { return fmt.Sprintf("MyError occurred with parameter: %d", m.Param) } var err error = &MyError{Param: 5} var myErr *MyError if errors.As(err, &myErr) { // 处理 MyError 类型的错误 fmt.Println(myErr.Param) // 输出错误中的参数 }
总结
-
errors.Unwrap
用于获取包装的底层错误。 -
errors.Is
用于检查错误是否匹配特定的错误。 -
errors.As
用于将错误转换为具体的类型,以便进行详细的检查和操作。
Panic
恢复函数recover只能在延迟调用内正确执行,直接注册为延迟执行或者延迟函数间接调用都无法不或恐慌
func catch() { recover() } func main() { defer catch() // 有效!在延迟函数内直接调用。 // defer log.Println(recover()) // 无效!作为参数立即执行。//简介调用 // defer recover() // 无效!被直接注册为延迟调用。 panic("p!") }
recover一定要在延迟调用的函数体内被调用
func main() { defer func() { log.Println(recover()) // 捕获第二次:p2 }() func() { defer func(){ panic("p2") // 第二次! }() defer func() { log.Println(recover()) // 捕获第一次:p1 }() panic("p1") // 第一次! }() println("exit.") }