《讀書筆記系列》==> 《The Way to Go》 3

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

4.4 變數

4.4.1 簡介

聲明變數的一般形式是使用 var 關鍵字:var identifier type

需要注意的是,Go 和許多程式設計語言不同,它在聲明變數時將變數的類型放在變數的名稱之後。

Go 為什麼要選擇這麼做呢?
首先,它是為了避免像 C 語言中那樣含糊不清的聲明形式,例如:int* a, b;。在這個例子中,只有 a 是指標而 b 不是。如果你想要這兩個變數都是指標,則需要將它們分開書寫(你可以在 Go 語言的聲明文法 頁面找到有關於這個話題的更多討論)。

而在 Go 中,則可以和輕鬆地將它們都聲明為指標類型:

var a, b *int

其次,這種文法能夠按照從左至右的順序閱讀,使得代碼更加容易理解。

樣本:

var a intvar b boolvar str string

你也可以改寫成這種形式:

var (a intb boolstr string)

這種因式分解關鍵字的寫法一般用於聲明全域變數。

當一個變數被聲明之後,系統自動賦予它該類型的零值:int 為 0,float 為 0.0,bool 為 false,string 為空白字串,指標為 nil。

記住,所有的記憶體在 Go 中都是經過初始化的。

變數的命名規則遵循駱駝命名法,即首個單詞小寫,每個新單詞的首字母大寫,例如:numShipsstartDate

但如果你的全域變數希望能夠被外部包所使用,則需要將首個單詞的首字母也大寫(第 4.2 節:可見度規則)。

一個變數(常量、類型或函數)在程式中都有一定的作用範圍,稱之為範圍。

如果一個變數在函數體外聲明,則被認為是全域變數,可以在整個包甚至外部包(被匯出後)使用,不管你聲明在哪個源檔案裡或在哪個源檔案裡調用該變數。

在函數體內聲明的變數稱之為局部變數,它們的範圍只在函數體內,參數和傳回值變數也是局部變數。

在第 5 章,我們將會學習到像 if 和 for 這些控制結構,而在這些結構中聲明的變數的範圍只在相應的代碼塊內。一般情況下,局部變數的範圍可以通過代碼塊(用大括弧括起來的部分)判斷。

儘管變數的標識符必須是唯一的,但你可以在某個代碼塊的內層代碼塊中使用相同名稱的變數,則此時外部的同名變數將會暫時隱藏(結束內部代碼塊的執行後隱藏的外部同名變數又會出現,而內部同名變數則被釋放),你任何的操作都只會影響內部代碼塊的局部變數。

var a 這種文法是不正確的,因為編譯器沒有任何可以用於自動推斷類型的依據。
變數的類型也可以在運行時實現自動推斷,例如:

var (HOME = os.Getenv("HOME")USER = os.Getenv("USER")GOROOT = os.Getenv("GOROOT"))

這種寫法主要用於聲明包層級的全域變數,當你在函數體內聲明局部變數時,應使用簡短聲明文法 :=,例如:

a := 1

4.4.2 實值型別和參考型別

所有像 int、float、bool 和 string 這些基本類型都屬於實值型別,使用這些類型的變數直接指向存在記憶體中的值:

另外,像數組(第 7 章)和結構(第 10 章)這些複合類型也是實值型別。

當使用等號 = 將一個變數的值賦值給另一個變數時,如:j = i,實際上是在記憶體中將 i 的值進行了拷貝:

你可以通過 &i 來擷取變數 i 的記憶體位址(第 4.9 節),例如:0xf840000040(每次的地址都可能不一樣)。實值型別的變數的值儲存在棧中。

記憶體位址會根據機器的不同而有所不同,甚至相同的程式在不同的機器上執行後也會有不同的記憶體位址。因為每台機器可能有不同的儲存空間布局,並且位置分配也可能不同。

更複雜的資料通常會需要使用多個字,這些資料一般使用參考型別儲存。

一個參考型別的變數 r1 儲存的是 r1 的值所在的記憶體位址(數字),或記憶體位址中第一個字所在的位置。

這個記憶體位址為稱之為指標(你可以從中很清晰地看到,第 4.9 節將會詳細說明),這個指標實際上也被存在另外的某一個字中。

同一個參考型別的指標指向的多個字可以是在連續的記憶體位址中(記憶體布局是連續的),這也是計算效率最高的一種儲存形式;也可以將這些字分散存放在記憶體中,每個字都指示了下一個字所在的記憶體位址。

當使用指派陳述式 r2 = r1 時,只有引用(地址)被複製。

如果 r1 的值被改變了,那麼這個值的所有引用都會指向被修改後的內容,在這個例子中,r2 也會受到影響。

在 Go 語言中,指標(第 4.9 節)屬於參考型別,其它的參考型別還包括 slices(第 7 章),maps(第 8 章)和 channel(第 13 章)。被引用的變數會儲存在堆中,以便進行記憶體回收,且比棧擁有更大的記憶體空間。

4.4.4 簡短形式,使用 := 賦值操作符

我們知道可以在變數的初始化時省略變數的類型而由系統自動推斷,而這個時候再在 Example 4.4.1 的最後一個聲明語句寫上 var 關鍵字就顯得有些多餘了,因此我們可以將它們簡寫為 a := 50b := false

a 和 b 的類型(int 和 bool)將由編譯器自動推斷。

但是全域變數是允許聲明但不使用。

其他的簡短形式為:

同一類型的多個變數可以聲明在同一行,如:

var a, b, c int   //聲明

(這是將類型寫在標識符後面的一個重要原因)

多變數可以在同一行進行賦值,如:

a, b, c = 5, 7, "abc"  //賦值

上面這行假設了變數 a,b 和 c 都已經被聲明,否則的話應該這樣使用:

a, b, c := 5, 7, "abc"  //(隱式)聲明 + 賦值

右邊的這些值以相同的順序賦值給左邊的變數,所以 a 的值是 5, b 的值是 7,c 的值是 "abc"

這被稱為 並行同時 賦值。

如果你想要交換兩個變數的值,則可以簡單地使用 a, b = b, a

(在 Go 語言中,這樣省去了使用交換函數的必要)

空白標識符 _ 也被用於拋棄值,如值 5 在:_, b = 5, 7 中被拋棄。

_ 實際上是一個唯寫變數,你不能得到它的值。這樣做是因為 Go 語言中你必須使用所有被聲明的變數,但有時你並不需要使用從一個函數得到的所有傳回值。

並行賦值也被用於當一個函數返回多個傳回值時,比如這裡的 val 和錯誤 err 是通過調用 Func1 函數同時得到:val, err = Func1(var1)

4.4.5 init 函數

變數除了可以在全域聲明中初始化,也可以在 init 函數中初始化。這是一類非常特殊的函數,它不能夠被人為調用,而是在每個包完成初始化後自動執行,並且執行優先順序比 main 函數高。

每一個源檔案都可以包含且只包含一個 init 函數。初始化總是以單線程執行,並且按照包的依賴關係順序執行。

一個可能的用途是在開始執行程式之前對資料進行檢驗或修複,以保證程式狀態的正確性。

樣本 4.6 init.go:

package transimport "math"var Pi float64func init() {   Pi = 4 * math.Atan(1) // init() function computes Pi}

在它的 init 函數中計算變數 Pi 的初始值。

樣本 4.7 user_init.go 中匯入了包 trans(在相同的路徑中)並且使用到了變數 Pi:

package mainimport (   "fmt"   "./trans")var twoPi = 2 * trans.Pifunc main() {   fmt.Printf("2*Pi = %g\n", twoPi) // 2*Pi = 6.283185307179586}

init 函數也經常被用在當一個程式開始之前調用後台執行的 goroutine,如下面這個例子當中的 backend()

func init() {   // setup preparations   go backend()}

練習 推斷以下程式的輸出,並解釋你的答案,然後編譯並執行它們。

練習 4.1 local_scope.go:

package mainvar a = "G"func main() {   n()   m()   n()}func n() { print(a) }func m() {   a := "O"   print(a)}

練習 4.2 global_scope.go:

package mainvar a = "G"func main() {   n()   m()   n()}func n() {   print(a)}func m() {   a = "O"   print(a)}

練習 4.3 function_calls_function.go

package mainvar a stringfunc main() {   a = "G"   print(a)   f1()}func f1() {   a := "O"   print(a)   f2()}func f2() {   print(a)}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.