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

Go 我应该在包级别但在http处理程序之外声明变量吗?,go,httprequest,httphandler,go-gin,Go,Httprequest,Httphandler,Go Gin,我正在使用gin gonic作为HTTP框架,我需要使用共享变量对一些路径进行分组,如下所示: ur := r.Group("/") ur.Use(package.Prepare) { ur.GET("/", package.Home) } 在Prepare处理程序中,我声明包变量如下 package.tplPath,因为我希望所有子路由都可以访问此变量,而不是重写每个http处理程序中的代码 var tplPath = ""

我正在使用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中,包是一种模块。对于任何给定的导入路径(基本上是包名),只有一个包实例。这意味着在包级别任何变量只有一个实例

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

包变量的类型(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之前运行,只运行一次。

请解释关于线程安全的更多细节,避免使用包级变量,因此如果我声明一个
struct
而不是
tplPath
,它会工作吗,就像刚刚测试过的
type pack struct{tplPath string}
一样,就像你是正确的一样,声明的变量可以从其他请求访问。如果使用
init()
一次性声明包级变量,那么我不会在运行时修改这个变量,在这种情况下
tplPath
是一个私有变量,这意味着它不能从包的外部更改。或者,在请求之间共享变量的正确方法是什么?Init更像是一种“设置”功能;对于首先实例化变量而言,它不会解决您在同一时间读取和写入同一内存的问题,就像在获取/设置变量时使用互斥锁锁定和解锁一样?是的,使用互斥锁可以防止数据竞争;但是,通常您会想尝试重新构建问题或代码,这样您就不需要首先共享内存。避免许多东西需要读写相同的值