<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 4.4.1 簡介 聲明變量的一般形式是使用?`var`?關鍵字:`var identifier type`。 需要注意的是,Go 和許多編程語言不同,它在聲明變量時將變量的類型放在變量的名稱之后。Go 為什么要選擇這么做呢? 首先,它是為了避免像 C 語言中那樣含糊不清的聲明形式,例如:`int* a, b;`。在這個例子中,只有 a 是指針而 b 不是。如果你想要這兩個變量都是指針,則需要將它們分開書寫(你可以在?[Go 語言的聲明語法](http://blog.golang.org/2010/07/gos-declaration-syntax.html)?頁面找到有關于這個話題的更多討論)。 而在 Go 中,則可以和輕松地將它們都聲明為指針類型: ~~~ var a, b *int ~~~ 其次,這種語法能夠按照從左至右的順序閱讀,使得代碼更加容易理解。 示例: ~~~ var a int var b bool var str string ~~~ 你也可以改寫成這種形式: ~~~ var ( a int b bool str string ) ~~~ 這種因式分解關鍵字的寫法一般用于聲明全局變量。 當一個變量被聲明之后,系統自動賦予它該類型的零值:int 為 0,float 為 0.0,bool 為 false,string 為空字符串,指針為 nil。記住,所有的內存在 Go 中都是經過初始化的。 變量的命名規則遵循駱駝命名法,即首個單詞小寫,每個新單詞的首字母大寫,例如:`numShips`?和?`startDate`。 但如果你的全局變量希望能夠被外部包所使用,則需要將首個單詞的首字母也大寫(第 4.2 節:可見性規則)。 一個變量(常量、類型或函數)在程序中都有一定的作用范圍,稱之為作用域。如果一個變量在函數體外聲明,則被認為是全局變量,可以在整個包甚至外部包(被導出后)使用,不管你聲明在哪個源文件里或在哪個源文件里調用該變量。 在函數體內聲明的變量稱之為局部變量,它們的作用域只在函數體內,參數和返回值變量也是局部變量。在第 5 章,我們將會學習到像 if 和 for 這些控制結構,而在這些結構中聲明的變量的作用域只在相應的代碼塊內。一般情況下,局部變量的作用域可以通過代碼塊(用大括號括起來的部分)判斷。 盡管變量的標識符必須是唯一的,但你可以在某個代碼塊的內層代碼塊中使用相同名稱的變量,則此時外部的同名變量將會暫時隱藏(結束內部代碼塊的執行后隱藏的外部同名變量又會出現,而內部同名變量則被釋放),你任何的操作都只會影響內部代碼塊的局部變量。 變量可以編譯期間就被賦值,賦值給變量使用運算符等號?`=`,當然你也可以在運行時對變量進行賦值操作。 示例: ~~~ a = 15 b = false ~~~ 一般情況下,只有類型相同的變量之間才可以相互賦值,例如: ~~~ a = b ~~~ 聲明與賦值(初始化)語句也可以組合起來。 示例: ~~~ var identifier [type] = value var a int = 15 var i = 5 var b bool = false var str string = "Go says hello to the world!" ~~~ 但是 Go 編譯器的智商已經高到可以根據變量的值來自動推斷其類型,這有點像 Ruby 和 Python 這類動態語言,只不過它們是在運行時進行推斷,而 Go 是在編譯時就已經完成推斷過程。因此,你還可以使用下面的這些形式來聲明及初始化變量: ~~~ var a = 15 var b = false var str = "Go says hello to the world!" ~~~ 或: ~~~ var ( a = 15 b = false str = "Go says hello to the world!" numShips = 50 city string ) ~~~ 不過自動推斷類型并不是任何時候都適用的,當你想要給變量的類型并不是自動推斷出的某種類型時,你還是需要顯式指定變量的類型,例如: ~~~ var n int64 = 2 ~~~ 然而,`var a`?這種語法是不正確的,因為編譯器沒有任何可以用于自動推斷類型的依據。變量的類型也可以在運行時實現自動推斷,例如: ~~~ var ( HOME = os.Getenv("HOME") USER = os.Getenv("USER") GOROOT = os.Getenv("GOROOT") ) ~~~ 這種寫法主要用于聲明包級別的全局變量,當你在函數體內聲明局部變量時,應使用簡短聲明語法?`:=`,例如: ~~~ a := 1 ~~~ 下面這個例子展示了如何在運行時獲取所在的操作系統類型,它通過?`os`?包中的函數?`os.Getenv()`?來獲取環境變量中的值,并保存到 string 類型的局部變量 path 中。 示例 4.5?[goos.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/goos.go) ~~~ package main import ( "fmt" "os" ) func main() { var goos string = os.Getenv("GOOS") fmt.Printf("The operating system is: %s\n", goos) path := os.Getenv("PATH") fmt.Printf("Path is %s\n", path) } ~~~ 如果你在 Windows 下運行這段代碼,則會輸出?`The operating system is: windows`?以及相應的環境變量的值;如果你在 Linux 下運行這段代碼,則會輸出?`The operating system is: linux`?以及相應的的環境變量的值。 這里用到了?`Printf`?的格式化輸出的功能(第 4.4.3 節)。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.4.md#442-值類型和引用類型)4.4.2 值類型和引用類型 程序中所用到的內存在計算機中使用一堆箱子來表示(這也是人們在講解它的時候的畫法),這些箱子被稱為 “ 字 ”。根據不同的處理器以及操作系統類型,所有的字都具有 32 位(4 字節)或 64 位(8 字節)的相同長度;所有的字都使用相關的內存地址來進行表示(以十六進制數表示)。 所有像 int、float、bool 和 string 這些基本類型都屬于值類型,使用這些類型的變量直接指向存在內存中的值: [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/4.4.2_fig4.1.jpg?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/4.4.2_fig4.1.jpg?raw=true) 另外,像數組(第 7 章)和結構(第 10 章)這些復合類型也是值類型。 當使用等號?`=`?將一個變量的值賦值給另一個變量時,如:`j = i`,實際上是在內存中將 i 的值進行了拷貝: [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/4.4.2_fig4.2.jpg?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/4.4.2_fig4.2.jpg?raw=true) 你可以通過 &i 來獲取變量 i 的內存地址(第 4.9 節),例如:0xf840000040(每次的地址都可能不一樣)。值類型的變量的值存儲在棧中。 內存地址會根據機器的不同而有所不同,甚至相同的程序在不同的機器上執行后也會有不同的內存地址。因為每臺機器可能有不同的存儲器布局,并且位置分配也可能不同。 更復雜的數據通常會需要使用多個字,這些數據一般使用引用類型保存。 一個引用類型的變量 r1 存儲的是 r1 的值所在的內存地址(數字),或內存地址中第一個字所在的位置。 [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/4.4.2_fig4.3.jpg?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/4.4.2_fig4.3.jpg?raw=true) 這個內存地址為稱之為指針(你可以從上圖中很清晰地看到,第 4.9 節將會詳細說明),這個指針實際上也被存在另外的某一個字中。 同一個引用類型的指針指向的多個字可以是在連續的內存地址中(內存布局是連續的),這也是計算效率最高的一種存儲形式;也可以將這些字分散存放在內存中,每個字都指示了下一個字所在的內存地址。 當使用賦值語句?`r2 = r1`?時,只有引用(地址)被復制。 如果 r1 的值被改變了,那么這個值的所有引用都會指向被修改后的內容,在這個例子中,r2 也會受到影響。 在 Go 語言中,指針(第 4.9 節)屬于引用類型,其它的引用類型還包括 slices(第 7 章),maps(第 8 章)和 channel(第 13 章)。被引用的變量會存儲在堆中,以便進行垃圾回收,且比棧擁有更大的內存空間。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.4.md#443-打印)4.4.3 打印 函數?`Printf`?可以在 fmt 包外部使用,這是因為它以大寫字母 P 開頭,該函數主要用于打印輸出到控制臺。通常使用的格式化字符串作為第一個參數: ~~~ func Printf(format string, list of variables to be printed) ~~~ 在示例 4.5 中,格式化字符串為:`"The operating system is: %s\n"`。 這個格式化字符串可以含有一個或多個的格式化標識符,例如:`%..`,其中?`..`?可以被不同類型所對應的標識符替換,如`%s`?代表字符串標識符、`%v`?代表使用類型的默認輸出格式的標識符。這些標識符所對應的值從格式化字符串后的第一個逗號開始按照相同順序添加,如果參數超過 1 個則同樣需要使用逗號分隔。使用這些占位符可以很好地控制格式化輸出的文本。 函數?`fmt.Sprintf`?與?`Printf`?的作用是完全相同的,不過前者將格式化后的字符串以返回值的形式返回給調用者,因此你可以在程序中使用包含變量的字符串,具體例子可以參見示例 15.4?[simple_tcp_server.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_15/simple_tcp_server.go)。 函數?`fmt.Print`?和?`fmt.Println`?會自動使用格式化標識符?`%v`?對字符串進行格式化,兩者都會在每個參數之間自動增加空格,而后者還會在字符串的最后加上一個換行符。例如: ~~~ fmt.Print("Hello:", 23) ~~~ 將輸出:`Hello: 23`。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.4.md#444-簡短形式使用--賦值操作符)4.4.4 簡短形式,使用 := 賦值操作符 我們知道可以在變量的初始化時省略變量的類型而由系統自動推斷,而這個時候再在 Example 4.4.1 的最后一個聲明語句寫上?`var`?關鍵字就顯得有些多余了,因此我們可以將它們簡寫為?`a := 50`?或?`b := false`。 a 和 b 的類型(int 和 bool)將由編譯器自動推斷。 這是使用變量的首選形式,但是它只能被用在函數體內,而不可以用于全局變量的聲明與賦值。使用操作符?`:=`?可以高效地創建一個新的變量,稱之為初始化聲明。 **注意事項** 如果在相同的代碼塊中,我們不可以再次對于相同名稱的變量使用初始化聲明,例如:`a := 20`?就是不被允許的,編譯器會提示錯誤?`no new variables on left side of :=`,但是?`a = 20`?是可以的,因為這是給相同的變量賦予一個新的值。 如果你在定義變量 a 之前使用它,則會得到編譯錯誤?`undefined: a`。 如果你聲明了一個局部變量卻沒有在相同的代碼塊中使用它,同樣會得到編譯錯誤,例如下面這個例子當中的變量 a: ~~~ func main() { var a string = "abc" fmt.Println("hello, world") } ~~~ 嘗試編譯這段代碼將得到錯誤?`a declared and not used`。 此外,單純地給 a 賦值也是不夠的,這個值必須被使用,所以使用?`fmt.Println("hello, world", a)`?會移除錯誤。 但是全局變量是允許聲明但不使用。 其他的簡短形式為: 同一類型的多個變量可以聲明在同一行,如: ~~~ 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)`。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/04.4.md#445-init-函數)4.4.5 init 函數 變量除了可以在全局聲明中初始化,也可以在 init 函數中初始化。這是一類非常特殊的函數,它不能夠被人為調用,而是在每個包完成初始化后自動執行,并且執行優先級比 main 函數高。 每一個源文件都可以包含且只包含一個 init 函數。初始化總是以單線程執行,并且按照包的依賴關系順序執行。 一個可能的用途是在開始執行程序之前對數據進行檢驗或修復,以保證程序狀態的正確性。 示例 4.6?[init.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/init.go): ~~~ package trans import "math" var Pi float64 func init() { Pi = 4 * math.Atan(1) // init() function computes Pi } ~~~ 在它的 init 函數中計算變量 Pi 的初始值。 示例 4.7?[user_init.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/user_init.go)?中導入了包 trans(在相同的路徑中)并且使用到了變量 Pi: ~~~ package main import ( "fmt" "./trans" ) var twoPi = 2 * trans.Pi func 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](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/local_scope.go): ~~~ package main var a = "G" func main() { n() m() n() } func n() { print(a) } func m() { a := "O" print(a) } ~~~ 練習 4.2?[global_scope.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/global_scope.go): ~~~ package main var a = "G" func main() { n() m() n() } func n() { print(a) } func m() { a = "O" print(a) } ~~~ 練習 4.3?[function_calls_function.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_4/function_calls_function.go) ~~~ package main var a string func main() { a = "G" print(a) f1() } func f1() { a := "O" print(a) f2() } func f2() { print(a) } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看