2016-07-24 143 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時都會重新創建該變量。