原创分享 15.Go 语言 --- 函数是 “一等公民”

happy_brother · 2021年01月21日 · 63 次阅读

本文视频地址

一 函数可以怎么用

1 在函数内创建
$GOROOT/src/runtime/print.go
func hexdumpWords(p, end uintptr, mark func(uintptr) byte) {
        p1 := func(x uintptr) {
                var buf [2 * sys.PtrSize]byte
                for i := len(buf) - 1; i >= 0; i-- {
                        if x&0xF < 10 {
                                buf[i] = byte(x&0xF) + '0'
                        } else {
                                buf[i] = byte(x&0xF) - 10 + 'a'
                        }
                        x >>= 4
                }
                gwrite(buf[:])
        }
    ...
}

在 hexdumpWords 函数内部,变量 p1 被匿名函数赋值。

2 作为类型

使用函数来自定义类型

$GOROOT/src/net/http/server.go
type HandlerFunc func(ResponseWriter, *Request)
3 存储到变量中
$GOROOT/src/runtime/vdso_linux.go
func vdsoParseSymbols(info *vdsoInfo, version int32) {
        if !info.valid {
                return
        }

        apply := func(symIndex uint32, k vdsoSymbolKey) bool {
                sym := &info.symtab[symIndex]
                typ := _ELF_ST_TYPE(sym.st_info)
                bind := _ELF_ST_BIND(sym.st_info)
        ... 
                *k.ptr = info.loadOffset + uintptr(sym.st_value)
                return true
        }
    ...
}
4 作为参数传入函数
$GOROOT/src/time/sleep.go

func AfterFunc(d Duration, f func()) *Timer {
        t := &Timer{
                r: runtimeTimer{
                        when: when(d),
                        f:    goFunc,
                        arg:  f,
                },
        }
        startTimer(&t.r)
        return t
}
5.作为返回值从函数返回
$GOROOT/src/strings/strings.go
func makeCutsetFunc(cutset string) func(rune) bool {
        if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
                return func(r rune) bool {
                        return r == rune(cutset[0])
                }
        }
        if as, isASCII := makeASCIISet(cutset); isASCII {
                return func(r rune) bool {
                        return r < utf8.RuneSelf && as.contains(byte(r))
                }
        }
        return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}

二 函数作为 “一等公民” 的特殊运用

1. 像整型变量那样对函数进行显式转型
func Welcome(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, “欢迎来到Go语言的世界!\n")
}                    

func main() {
        http.ListenAndServe(":8080", http.HandlerFunc(Welcome))
}


$GOROOT/src/net/http/server.go
func ListenAndServe(addr string, handler Handler) error {
        server := &Server{Addr: addr, Handler: handler}
        return server.ListenAndServe()
}

可以看到 ListenAndServe 方法的第二个参数 handler ,而这里 handler 参数的类型 http.Handler 接口。

$GOROOT/src/net/http/server.go
type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}

http.Handler 接口只有一个 ServeHTTP 方法,我们可以看到它的原型是 func(http.ResponseWriter, *http.Request),与 Welcome 原型一模一样。


$GOROOT/src/net/http/server.go
type HandlerFunc func(ResponseWriter, *Request)

//ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
}

HandlerFunc 实现了 ServeHTTP 方法,也就实现了 Handler 接口,函数 Welcome 显式转换为 HandlerFunc 类型。

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册