函数以及其闭包和错误处理

函数

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
​
}

闭包

是一个函数值,引用了其函数体之外的变量(闭包可以访问外部函数内的变量

  1. 保持状态:闭包可以用来创建具有状态的函数。函数内部的变量可以在多次调用之间保持其状态,而不需要全局变量。

保持状态:
​
闭包可以用于创建具有状态的函数。例如,您可以创建一个计数器函数,每次调用它都会增加计数值并返回。这种方式可以避免使用全局变量来维护状态。
​
go
Copy code
func createCounter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

  1. 封装数据:闭包可以用于隐藏数据,只允许通过特定的函数来访问和修改数据。这有助于实现数据封装和隐藏细节。

  2. 回调函数:在异步编程中,闭包常常用作回调函数,以便在稍后的时间执行某些操作。

延迟调用

注册非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.")
​
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值