怎么理解:var *** func()

ggsmida · 2017-06-01 02:14:40 · 3964 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2017-06-01 02:14:40 的主题,其中的信息可能已经有所发展或是发生改变。

最近在阅读Kubernetes早期版本的源码,发现var *** func()的写法,请问这种写法该如何理解?有什么好处吗?

var testHookServerServe func(*Server, net.Listener) // used if non-nil

func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    if fn := testHookServerServe; fn != nil {
        fn(srv, l)
    }
...
}

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3964 次点击  
加入收藏 微博
11 回复  |  直到 2017-07-18 07:28:26
polaris
polaris · #1 · 8年之前

你就理解为 func 是一个类型,比如,把 func 当做 string,就理解了。Go中 func 是第一公民

ggsmida
ggsmida · #2 · 8年之前
polarispolaris #1 回复

你就理解为 func 是一个类型,比如,把 func 当做 string,就理解了。Go中 func 是第一公民

可是func没有指明对参数的具体处理,最后的fn(srv, l)算是什么呢?既没有处理,也没有返回,就只传了两个参数吗?

polaris
polaris · #3 · 8年之前

func 规定了一个方法签名,任何符合这个签名的 func 都可以赋值给它,具体的 func 会有方法体。这里 fn(srv, l) 就是函数调用啊。这里的代码,肯定有一处会给 testHookServerServe 这个变量赋值。

ggsmida
ggsmida · #4 · 8年之前
polarispolaris #3 回复

func 规定了一个方法签名,任何符合这个签名的 func 都可以赋值给它,具体的 func 会有方法体。这里 fn(srv, l) 就是函数调用啊。这里的代码,肯定有一处会给 testHookServerServe 这个变量赋值。

嗯,明白了,非常感谢!

631768417
631768417 · #5 · 8年之前
ggsmidaggsmida #4 回复

#3楼 @polaris 嗯,明白了,非常感谢!

类似与js里面的function 你写过js的话应该知道js也可以这么传function。。。。 原理一样

linkdesu
linkdesu · #6 · 8年之前

肯定有一处会给 testHookServerServe 这个变量赋值

@polaris 我看了看代码,代码中并没有类似 testHookServerServe := xxx 这样的赋值发生啊,那请问 fn := testHookServerServe 具体的值又是从哪来的呢?我也是初学者非常疑惑,所以请见谅~~

polaris
polaris · #7 · 8年之前
linkdesulinkdesu #6 回复

> 肯定有一处会给 testHookServerServe 这个变量赋值 @polaris 我看了看代码,代码中并没有类似 `testHookServerServe := xxx` 这样的赋值发生啊,那请问 `fn := testHookServerServe` 具体的值又是从哪来的呢?我也是初学者非常疑惑,所以请见谅~~

我刚查了下最新版本的代码,里面没有 testHookServerServe 了,请提供你看的 Kubernetes 代码版本

linkdesu
linkdesu · #8 · 8年之前
polarispolaris #7 回复

#6楼 @linkdesu 我刚查了下最新版本的代码,里面没有 `testHookServerServe` 了,请提供你看的 Kubernetes 代码版本

额,不好意思我是在 go 语言的标准 net/http/server.go 里看到的相同代码,不过真的是完全一样~

linkdesu
linkdesu · #9 · 8年之前

这个其中代码的部分截取,我用文本查找确定了只有这两块代码出现过 testHookServerServe

var testHookServerServe func(*Server, net.Listener) // used if non-nil
...

// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call srv.Handler to reply to them.
//
// For HTTP/2 support, srv.TLSConfig should be initialized to the
// provided listener's TLS Config before calling Serve. If
// srv.TLSConfig is non-nil and doesn't include the string "h2" in
// Config.NextProtos, HTTP/2 support is not enabled.
//
// Serve always returns a non-nil error. After Shutdown or Close, the
// returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    if fn := testHookServerServe; fn != nil {
        fn(srv, l)
    }
    var tempDelay time.Duration // how long to sleep on accept failure

    if err := srv.setupHTTP2_Serve(); err != nil {
        return err
    }

    srv.trackListener(l, true)
    defer srv.trackListener(l, false)

    baseCtx := context.Background() // base is always background, per Issue 16220
    ctx := context.WithValue(baseCtx, ServerContextKey, srv)
    ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())
    for {
        rw, e := l.Accept()
        if e != nil {
            select {
            case <-srv.getDoneChan():
                return ErrServerClosed
            default:
            }
            if ne, ok := e.(net.Error); ok && ne.Temporary() {
                if tempDelay == 0 {
                    tempDelay = 5 * time.Millisecond
                } else {
                    tempDelay *= 2
                }
                if max := 1 * time.Second; tempDelay > max {
                    tempDelay = max
                }
                srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
                time.Sleep(tempDelay)
                continue
            }
            return e
        }
        tempDelay = 0
        c := srv.newConn(rw)
        c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve(ctx)
    }
}
polaris
polaris · #10 · 8年之前
linkdesulinkdesu #8 回复

#7楼 @polaris 额,不好意思我是在 go 语言的标准 net/http/server.go 里看到的相同代码,不过真的是完全一样~

我大概看了下,这个变量只是为了测试使用的(为测试留的钩子),而且代码注释很清晰:used if non-nil,所以,只有在测试代码中有。

http://docs.studygolang.com/src/net/http/export_test.go?s=1568:1590#L58

具体调用 SetTestHookServerServe 的,在 net/http/serve_test.go 中。

linkdesu
linkdesu · #11 · 8年之前

哦!十分感谢!!!看来这个问题是我对 go 的作用域理解还不够造成的!

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传