我应该在包级别但在 http 处理程序之外声明变量吗?

Should I declare variables in package level but outside of http handler?

我正在使用 gin gonic 作为 HTTP 框架,我需要像这样用共享变量对一些路径进行分组:

ur := r.Group("/")
ur.Use(package.Prepare)
{
    ur.GET("/", package.Home)
}

Prepare 处理程序中,我将包变量声明为 package.tplPath 因为我希望所有的子路由都可以访问这个变量,而不是在每个 http 处理程序中重写代码。

var tplPath = ""

func Prepare(c *gin.Context) {
    _, filename, _, _ := runtime.Caller(0)
    s := helper.RelativeFilePath(filename)
    tplPath = s[1:len(s)] + "template/"
}

我不知道 Go 如何处理每个进程,以及每个 http 请求的变量。如果在包级别声明变量,是否会在每次 http 请求后设置?

这被认为是好的做法吗?如果不是,为什么不呢?

这不是线程安全的,包变量在所有 goroutine 之间共享,修改一个例程会更改所有其他例程中的值,从而导致数据竞争。

一般;尽可能避免使用包级变量。

编辑:

在go中,包是一种模块。对于任何给定的导入路径(基本上是包名称),只存在一个包实例。这意味着在包级别只有 1 个变量实例。

包变量是共享的全局状态。该变量的所有访问器都将访问完全相同的内存。

包变量是什么类型并不重要,struct / string / int 等。如果它是在包级别定义的,该变量的所有访问器将共享它的同一个实例。

如果(对于 http 服务器)您有并发代码,那么该变量将同时有多个访问器。在某些情况下,这很好,例如仅读取该变量时,但在您的情况下,它似乎会被修改。让这段代码变得活泼!

tplPath是一个全局变量,所有例程都会访问相同的内存地址,并在每次http请求后设置。 如果您只想设置一次,并且 tplPath 不依赖于 http 请求。可以在init函数中设置。

func init(){
    _, filename, _, _ := runtime.Caller(0)
    s := helper.RelativeFilePath(filename)
    tplPath = s[1:len(s)] + "template/"
}

init函数会运行在main之前,只做一次。