我多次听说你应该避免全局变量。
在我的例子中,我声明了一个全局myTypes
变量,只是为了避免在函数调用或类似事件中反复声明该变量。
这是怎么做的?有没有更好的办法?一种更可测试的方式?
var myTypes = map[string]string{
"type1": "tpl1",
"type2": "tpl2",
}
func AFunc(someType string) string {
fmt.Sprintf("this is your type %s", myTypes[someType])
}
func main() {
AFunc("type1")
}
答案 0 :(得分:7)
并非所有全局变量都不好。在你的情况下:
main
包中,因此只能由单个程序访问。没关系。另一方面,每当在程序执行期间修改全局变量时,程序就变得更难理解。因此应该避免。
在一个可重用的包中,应该避免全局变量,因为那个包的两个用户可能会相互影响。想象一下,如果json
包具有全局变量var Indent bool
。这样的变量最好隐藏在像JsonFormatter
这样的数据结构中,每当有人想要格式化一些JSON时,它就会重新创建。
答案 1 :(得分:6)
一种常用方法是使用Method Value
考虑
struct type T
使用两种方法Mv
,其接收方类型为T
,Mp
,其接收方类型为*T
。< / p>
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
表达式
T.Mv
产生一个等效于Mv的函数,但显式接收器作为其第一个参数;它有签名
func(tv T, a int) int
您可以看到方法值in this thread
的示例// TODO: Get rid of the global variable.
var foo service
func handleFoo(w http.ResponseWriter, req *http.Request) {
// code that uses foo
}
func main() {
foo = initFoo()
http.HandleFunc("/foo", handleFoo)
}
摆脱全局变量的一种方法是使用方法值:
type fooHandler struct {
foo service
}
func (h fooHandler) handle(w http.ResponseWriter, req *http.Request) {
// code that uses h.foo
}
func main() {
foo := initFoo()
http.HandleFunc("/foo", fooHandler{foo}.handle)
}
Go 1.7中引入了context.Context#Values
的全新价值观的新官方方法。
仅将上下文值用于转换进程和API的请求范围数据,而不是将可选参数传递给函数。
请参阅“How to correctly use context.Context in Go 1.7”
最后,除了难以测试之外,全球价值可以阻止销售。
请参阅“To vendor or not to vendor, that is a question”
许多Go的库已导出包变量。这些变量可以被视为某个包的某些全局状态。
在此之前的销售时代,我们可以获取每个导入的包一次,并且可以在所有其他导入的包中共享每个导入包的全局状态。
一些开发者可能会认为它是理所当然的,只是随意操纵这些全球状态 但是,对每个导入的包进行销售可能有自己的全局状态视图。现在开发者可能发现无法改变其他包的全局状态视图
答案 2 :(得分:0)
您无需修改myTypes
,而只是阅读它,因此它根本不是变量,它是一个常数,并且如果Go支持它,则将其定义为此类(并确保您不对其进行突变) -不幸的是,Go不允许您像其他语言一样强制执行“ constness”)。全局常数通常都很好。
如果您要修改myTypes
,例如通过提供一个在运行时添加新类型的功能,那么是的,将myTypes
保留为全局状态是一个坏主意。只要您仅在“主程序”中执行此操作,您就可能会摆脱它,确定不会将其作为其他代码导入的包,但是您不知道该代码可能在哪里结束/被复制到(甚至只是从同一包中的多个位置使用),所以为什么要冒险。如果这成为一个由其他软件包导入的软件包,则只要运行时活动的“客户端”软件包不超过一个,就可以正常工作,但是只要有人将多个此类软件包链接到一个二进制文件中,所有这些用户程序包将使全局myTypes
中彼此的数据脚。如果一个客户程序包只希望看到它早些时候放入的myTypes
,那么如果另一个客户的期望值不同,这将中断。因此,单独使用时可以正常工作的程序包一起使用时可能会损坏,除非更改共享代码,否则无法解决此问题。因此,请不要这样做。令人遗憾的是,Google自己在自己的某些公共物品中使用了全球状态,例如在标准的“标志”包中,使用诸如“ glog”之类的东西,从而继承了问题。不要这样做。