Go 語言,使用變量之前需要先進行變量的聲明。
var s string = “Golang"n := 666
Go 語言有兩類變量
? ? ? ? 包級別(package varible):在 package 級別可見的變量。如果是導出變量,該變量也可以被視為全局變量;
? ? ? ? 局部變量(local varible):函數或方法體內聲明的變量,僅在函數或方法體內可見。
1. 包級別變量
包級變量使用var 關鍵字的變量聲明形式,從變量聲明的時候是否延遲初始化這個角度對包級變量進行一次分類。
1). 聲明并同時顯式初始化
//$GOROOT/src/io/pipe.govar ErrClosedPipe = errors.New("io: read/write on closed pipe")//$GOROOT/src/io/io.govar EOF = errors.New("EOF”)
上面,對于變量聲明的同時進行顯式初始化的這類包級變量,格式:
? ? ? ? ????var 變量名 = 初始化表達式
編譯器會自動根據等號右側 初始化表達式 結果值的類型確定左側聲明的變量的類型。
var?num?=?16var pi = 3.14
?Go 會為包級變量設置默認類型,對于未顯式賦予類型的整型變量 num,編譯器會設置默認類型 int;而浮點型變量 pi 的默認類型則為 float64。如果不想使用默認類型,而是要顯式為 num 和 pi 指定類型。
var num = int32(16)var pi = float64(3.14)
上面是默認類型和顯式指定類型兩種聲明形式,尤其是在將這些變量放在一個 var 塊中聲明時
var ( num = 17 pi = float32(3.14))
2). 延遲初始化
? ? ? ? 有時候,聲明并不立即顯式初始化的包級變量,雖然沒有顯式初始化,Go 語言也會讓這些變量擁有初始的“零值”。如果是自定義的類型,保證其零值可用是非常必要的,形式如下:
var a int32var f float64
3). 聲明聚類與就近原則
??? Go 語言提供 var 塊用于將多于一個的變量聲明放在一起,我們習慣:
??????? 1 將同一類的變量聲明放在一個 var 塊中,不同類的聲明放在不同的 var 塊中;
??????? 2 將延遲初始化的變量聲明放在一個 var 塊,而將聲明且顯式初始化的變量放在另一個 var 塊中。
Go 標準庫中的代碼:
// $GOROOT/src/net/http/server.govar ( bufioReaderPool sync.Pool bufioWriter2kPool sync.Pool bufioWriter4kPool sync.Pool)var copyBufPool = sync.Pool{ New: func() interface{} { b := make([]byte, 32*1024) return &b },}
copyBufPool 變量沒有放入 var 塊就是因為它的聲明是帶有顯式初始化的,而 var 塊中的變量聲明都是延遲初始化的
// $GOROOT/src/net/net.govar ( aLongTimeAgo = time.Unix(1, 0) noDeadline = time.Time{} noCancel = (chan struct{})(nil))var threadLimit chan struct{}
threadLimit 單獨放在 var 塊外面,它是延遲初始化的變量聲明,它與以上的 var 塊中時間限制的變量也有所不同。
變量聲明最佳實踐中還有一個原則-就近原則,如果一個包級變量在包內部多處使用,放在源文件頭部聲明比較恰當直觀。
/ $GOROOT/src/net/http/request.govar ErrNoCookie = errors.New("http: named cookie not present")func (r *Request) Cookie(name string) (*Cookie, error) { for _, c := range readCookies(r.Header, name) { return c, nil } return nil, ErrNoCookie}
2. 局部變量的聲明形式
比上面的包級別變量,局部變量多了短變量聲明形式,局部變量采用最多的一種聲明形式。
對于延遲初始化的局部變量聲明,用帶有 var 的聲明形式。
// $GOROOT/src/strings/replace.gofunc (r *byteReplacer) Replace(s string) string { var buf []byte // 延遲初始化 for i := 0; i < len(s); i++ { b := s[i] if r[b] != b { if buf == nil { buf = []byte(s) } buf[i] = r[b]????} } if buf == nil { return s } return string(buf)}
????var err error? 這也是我們日常常見的聲明方式
短變量聲明形式是局部變量最常用的聲明形式,在 Go 標準庫代碼中廣泛使用。?
num?:=?17?????????????//默認類型pi?:=?float32(3.14)???//顯示轉型
// $GOROOT/src/net/net.gofunc (v *Buffers) WriteTo(w io.Writer) (n int64, err error) { if wv, ok := w.(buffersWriter); ok { return wv.writeBuffers(v) } for _, b := range *v { nb, err := w.Write(b) n += int64(nb) if err != nil { v.consume(n) return n, err } } v.consume(n) return n, nil}
我們看到Go源代碼net中,if wv, ok := w.(buffersWriter); ok和for _, b := range *v都使用了短變量聲明形式,這也體現出“就近”原則,讓變量的作用域最小化。
設計良好的函數/方法的原則是“單一職責”,因此每個函數/方法規模都不大,很少需要應用 var 塊來聲明局部變量,如果你在聲明局部變量時遇到這種場景,那就使用 var 塊來聲明多于一個的局部變量吧。看一下Go標準庫中的源代碼是這么使用的:
// $GOROOT/src/net/dial.gofunc (r *Resolver) resolveAddrList(ctx context.Context, op, network,addr string, hint Addr) (addrList, error) { ... ... var ( tcp *TCPAddr udp *UDPAddr ip *IPAddr wildcard bool ) ... ...}