defer的妙用

defer是go关键字,一般用来清理释放资源,在了解go-kit微服务时,发现了有意思的用法

一般用法--清理释放资源

fd, err := os.Open(filename)
if err != nil {
    return
}
defer fd.Close()

使用defer可以避免忘记释放资源。曾经使用lsof -p $pid | grep deleted帮一个C++老手找出过程序资源句柄忘记Close的问题,go的defer可以有效避免此类问题。

defer的妙用--中间件MiddleWare

package main

import (
        "fmt"
        "io"
        "os"
        "strings"
        "time"
)

func main() {
    var svc stringService
    svc = &stringSvc{}
    svc = setupLogMiddle(os.Stdout)(svc)
    ret := svc.ToUpper("hello")
    fmt.Println(ret)
}

// 定义接口
type stringService interface {
    ToUpper(string) string
}

type stringSvc struct{}

// 真正的业务service
func (ss *stringSvc) ToUpper(input string) (ret string) {
    return strings.ToUpper(input)
}

// 中间件type
type middle func(stringService) stringService

type log struct {
    writer io.Writer
    stringService
}

// 安装中间件
func setupLogMiddle(writer io.Writer) middle {
    return func(ss stringService) stringService {
        return &log{writer, ss}
    }
}

func (l *log) ToUpper(input string) (ret string) {
    // 此处defer执行log中间件
    defer func(begin time.Time) {
        fmt.Fprintf(l.writer, "method: %s, input: %s, output: %s, took: %v\n",
            "ToUpper", input, ret, time.Since(begin))
    }(time.Now())

    ret = l.stringService.ToUpper(input)
    return ret
}

以上是从go-kit看到的,挺有意思,记录下来。