2016-07-24 150 views
6

我听说过很多次,你应该避免全局变量。当使用全局变量

在我的例子,我只宣布全球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") 
} 

回答

6

一种通常的方法是使用Method Value

考虑一个struct type T两种方法,Mv,其接收器是T类型,并且Mp,其接收器是*T类型。

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


最后,除了被硬考,全局值可以防止vendoring

请参阅 “To vendor or not to vendor, that is a question

许多Go的libaries已出口包变量。这些变量可以被看作某个包的某些全局状态。

之前的销售时代,我们可以一次获取每个导入的包,每个导入的包的全局状态可以在所有其他导入的包中共享。

一些开发者可能会认为它是理所当然的,并且可以随意操纵这些全局状态。
但是,与vendoring每个导入的包可能有自己的全局状态视图。现在开发人员可能发现无法更改其他软件包的全局状态视图

3

并非所有的全局变量都不好。在您的情况下:

  • 全局变量位于main包中,因此只能由单个程序访问。还行吧。
  • 全局变量初始化一次,之后未修改。还行吧。

另一方面,无论何时在程序执行过程中修改全局变量,程序变得更难理解。因此应该避免。

在,是为了被重用一个包,应避免全局变量,自那时起包的两个用户可能会相互影响。想象一下,如果json包有一个全局变量var Indent bool。这样的变量最好隐藏在像JsonFormatter这样的数据结构中,每次有人想格式化某些JSON时都会重新创建该变量。