从内部函数可以安全地引用外部函数中的值吗?

时间:2016-12-02 05:50:12

标签: go

我正在从Node.js转到Go,我担心我在Node中使用的构造在Go中是否安全,以及是否有更惯用的方法来完成同样的事情。我正在使用Echo框架,并希望设置一个特定于路由的结构,该结构将在上下文对象中可用。我可以为中间件中的每个调用生成结构,但这样做很昂贵。相反,我在外部函数中设置一次结构,然后返回一个内部函数,该函数引用外部函数中的结构。我的希望是,我只需要产生一次发电成本,然后为每次通话都有与我的路线相关的正确结构。

e.POST(path, POST.GenericPostHandler, func(next echo.HandlerFunc)  echo.HandlerFunc {
    operation := getOperationMap(path)
    return func(c echo.Context) error {
        c.Set("op", operation)
        return next(c)
    }
})

此代码是否有任何问题?它会导致GC出现问题吗?有没有更有效的方法来完成同样的事情?我假设每次调用中间件时都会生成结构的副本。

2 个答案:

答案 0 :(得分:1)

此代码是安全的,不会导致GC问题,并且是可以在Go中使用的良好的惯用模式。

在您的示例中,只有一个operation将被创建,移动到堆中,然后在每个请求由Echo处理时共享。

当我需要初始化一个在处理所有请求时将使用的昂贵结构时,我经常自己使用这个模型。

答案 1 :(得分:0)

如果operationMap在初始化后永远不会更改,您可以将operationMap声明为单例实例,如下所示:

package main

import (
    "fmt"
    "sync"
)

var (
    operationMapInst map[string]string // I don't know the exact type of map, so you should change the type.
    operationMapOnce sync.Once
)

func getOperationMap() map[string]string {
    // operationMapOnce.Do() runs only once
    // when the first time getOperationMap() is called.
    operationMapOnce.Do(func() {
        // Initialize operationMapInst.
        operationMapInst = map[string]string{"/": "root", "/ver": "version"}
        fmt.Println("operaionMap has initialized!")
    })

    return operationMapInst
}

func main() {
    // The initialization logic runs only once.
    // Because getOperationMap() returns map,
    // syntax for the value for a path should be getOperationMap()[path],
    // not getOperationMap(path).
    rootOp, ok := getOperationMap()["/"]
    fmt.Println(rootOp, ok)

    // repetition
    rootOp, ok = getOperationMap()["/"]
    fmt.Println(rootOp, ok)
    verOp, ok := getOperationMap()["/ver"]
    fmt.Println(verOp, ok)
    verOp, ok = getOperationMap()["/ver"]
    fmt.Println(verOp, ok)
}

您可以运行此代码here

我建议http://marcio.io/2015/07/singleton-pattern-in-go/了解Go中的单身模式。