首先但願學習 Go
語言的愛好者至少擁有其餘語言的編程經驗,若是是徹底零基礎的小白用戶,本教程可能並不適合閱讀或嘗試閱讀看看,系列筆記的目標是站在其餘語言的角度學習新的語言,理解 Go
語言,進而寫出真正的 Go
程序.java
編程語言中通常都有變量和常量的概念,對於學習新語言也是同樣,變量指的是不一樣編程語言的特殊之處,而常量就是編程語言的共同點.git
學習 Go
語言時儘量站在宏觀角度上分析變量,而常量可能一笑而過或者編程語言不夠豐富,所謂的常量其實也是變量,無論怎麼樣如今讓咱們開始 Go
語言的學習之旅吧,本教程涉及到的源碼已託管於 github
,如需獲取源碼,請直接訪問 https://github.com/snowdreams1006/learn-gogithub
Hello World
程序學習編程語言的第一件事就是編寫出 Hello World
,如今讓咱們用 Go
語言開發出第一個可運行的命令行程序吧!編程
環境前提準備能夠參考 走進Goland編輯器
新建 main
目錄,並新建 hello_world.go
文件,其中文件類型選擇 Simple Application
,編輯器會幫助咱們建立 Go
程序骨架.app
首先輸入 fmt
後觸發語法提示選擇 fmt.Println
,而後會自動導入 fmt
包.框架
完整內容以下,僅供參考:編程語言
package main import "fmt" func main() { fmt.Println("Hello World") }
點擊左側綠色啓動按鈕,能夠直接運行程序或者利用程序自帶的 Terminal
終端選項卡運行程序,固然也能夠用外部命令行工具運行程序.編輯器
go run
命令直接運行,而 go build
命令產生可執行文件,兩種方式都能如願以償輸出 Hello World
.ide
Go
應用程序入口的有如下要求:函數
main
包 :package main
main
方法 : func main()
main.go
,目錄名也任意不必定是 main
目錄.以上規則能夠很容易在編輯器中獲得驗證,任意一條不符合規則,程序都會報錯提示,這也是使用編輯器而不是命令行進行學習的緣由,可以幫助咱們及時發現錯誤,方便隨時驗證猜測.
總結來講,main
包不必定在 main
目錄下,main
方法能夠在任意文件中.
這也意味着程序入口所在的目錄不必定叫作 main
目錄卻必定要聲明爲 main
包,雖然不理解爲何這麼設計,這一點至少和 Java
徹底不同,至少意味着 Go
文件能夠直接遷移目錄而不須要語言層面的重構,可能有點方面,同時也有點疑惑?!
main
函數值得注意的不一樣之處:
main
函數不支持返回值,但能夠經過 os.Exit
返回退出狀態
main
函數,不支持返回值,若此時強行運行main
方法,則會報錯:func main must have no arguments and no return values
main
函數能夠藉助os.Exit(-1)
返回程序退出時狀態碼,外界能夠根據不一樣狀態碼識別相應狀態.
main
函數不支持傳入參數,但能夠經過 os.Args
獲取參數
在Terminal
終端選項卡中運行go run hello_world.go snowdreams1006
命令os.Args
輸出命令路徑和參數值.
The master has failed more times than the beginner has tried
計算機編程不是理科而是工科,動手親自實踐一遍才能更好地掌握知識技能,幸運的是,Go
語言自己內置提供了測試框架,不用加載第三方類庫擴展,很是有利於學習練習.
剛剛接觸 Go
語言,暫時不須要深刻講解如何編寫規範的測試程序,畢竟基礎語法還沒開始正式練習呢!
可是,簡單的規則仍是要說的,整體來講,只有兩條規則:
_test
結尾 : XXX_test.go
命令習慣和不一樣,Java
中的文件名通常是 大駝峯命名法,相應的測試文件是XXXTest
Test
開頭 : TestXXX
命名習慣和其餘編程語言不一樣,Java
中的測試方法命名是通常是 小駝峯命名法,相應的測試方法是testXXX
t *testing.T
其餘編程語言中通常沒有參數,Java
中的測試方法必定沒有參數,不然拋出異常java.lang.Exception: Method testXXX should have no parameters
新建 Go
文件,類型選擇 Empty File
,文件名命名爲 hello_world_test
,編輯器新建一個空白的測試文件.
此時編寫測試方法簽名,利用編輯器自動提示功能輸入 t.Log
隨便輸出些內容,這樣就完成了第一個測試文件.
和 main
程序同樣,測試方法也是可執行的,編輯器窗口的左側也會出現綠色啓動按鈕,運行測試用例在編輯器下方的控制檯窗口輸出 PASS
證實測試邏輯正確!
測試文件源碼示例:
package main import "testing" func TestHelloWorld(t *testing.T){ t.Log("Hello Test") }
如今已經學習了兩種基本方式,一種是把程序寫在 main
方法中,另外一種是把程序寫在測試方法中.
兩種方式均可以隨時測試驗證咱們的學習成果,若是寫在 main
方法中,知識點通常要包裝成單獨的方法,而後再在 main
方法中運行該方法.
若是寫在測試方法中,能夠單獨運行測試方法,而沒必要在 main
方法中一次性所有運行.
固然,這兩種方式均可以,只不過我的傾向於測試用例方式.
Fibonacci
數列形如 1,1,2,3,5,8,13,...
形式的數列就是斐波那契數列,特色是從三個元素開始,下一個元素的值就是前兩兩個元素值的總和,子子孫孫無窮盡也!
記得學習初中歷史時,關於昭君出塞的故事廣爲人知,王昭君的美貌不是這次討論的重點,而這次關注點是放到了昭君的悲慘人生.
漢朝和匈奴和親以換取邊境和平,漢朝皇帝不肯意本身的親閨女遠嫁塞北,因而從後宮中挑選了一名普通宮女充當和親對象,誰成想這名宮女竟長得如此美貌,"沉魚落雁閉月羞花",堪稱古代中國四大美女之一!
昭君擔負着和親重任,今後開始了遠離他鄉的悲慘生活,一路上,黃沙飛揚,燥熱憂傷,情之所至,昭君拿出隨性的琵琶,演奏出感人淚下的<<琵琶怨>>!
"千載琵琶做胡語,分明怨恨曲中論",可能情感過於哀傷,居然連天上的大雁都忘記了飛翔,所以收穫落雁之美!
老單于這個肥波納了個如花似玉的妾,作夢都能了醒吧,遺憾的是,命不久矣!
如此一來,昭君卻滿心歡喜,異族老公死了,使命完成了,應該能回到朝思夢想的大漢朝故土了吧?
命運弄人,匈奴文化,父死子繼,肥波已逝,但還有小肥波啊,放到漢朝倫理綱常來看,都不能叫作近親結婚了簡直是亂倫好嗎!
小肥波+昭君=小小肥波
,只要昭君不死,而昭君的現任老公不幸先死,那麼小小肥波又會繼續納妾生娃,理論上真的是子子孫孫無窮盡也!
肥波納妾故事可能長成這個樣子:
肥波,昭君,小肥波
昭君的第一任老公:
肥波+昭君=小肥波
,此時昭君剛生一個娃
肥波,小肥波,昭君,小小肥波
昭君的第二任老公:
小肥波+昭君=小小肥波
,昭君的娃娶了本身的媽?難怪昭君苦楚悲慘,有苦難言,幸運的是,此次昭君沒有生娃,兩個女孩!
肥波,小肥波,小小肥波,昭君
昭君的第三任老公,
小小肥波+昭君=小小小肥波
,兄終弟及,仍是亂倫好嗎,這輩分我是算不出來了.
肥波納妾系列,理論上和愚公移山有的一拼,生命不息,子承父業也好,兄終弟及也罷,數量愈來愈多,肚子愈來愈大.
以上故事,純屬虛構,昭君出塞是一件偉大的事情,換來了百年和平,值得尊敬.
迴歸正題,下面讓咱們用 Go
語言實現斐波那契數列吧!
func TestFib(t *testing.T) { var a = 1 var b = 1 fmt.Print(a) for i := 0; i < 6; i++ { fmt.Print(" ", b) temp := a a = b b = temp + b } fmt.Println() }
上述簡單示例,展現了變量的基本使用,簡單總結以下:
var
,類型名在前,變量類型在後,其中變量類型能夠省略.// 聲明變量a和變量b var a = 1 var b = 1
上述變量語法咋一看像是 Js
賦值,嚴格來講其實並非那樣,上面變量賦值形式只是下面這種的簡化
// 聲明變量a並指定類型爲 int,同理聲明變量b並指定類型爲int var a int = 1 var b int = 1
第一種寫法省略了 int
類型,由賦值 1
自動推斷爲 int
在必定程度上簡化了書寫,固然這種形式還能夠繼續簡化.
// 省略相同的 var,增長一對小括號 (),將變量放到小括號裏面 var ( a = 1 b = 1 )
可能問,還能不能繼續簡化下,畢竟其他語言的簡化形式可不是那樣的,答案是能夠的!
// 連續聲明變量並賦值 var a, b = 1, 1
固然,其他語言也有相似的寫法,這並不值得驕傲,下面這種形式纔是 Go
語言特有的精簡版形式.
// 省略了關鍵字var,賦值符號=改爲了:=,表示聲明變量並賦值 a, b := 1, 1
就問你服不服?一個小小的變量賦值都能玩出五種花樣,厲害了,個人 Go
!
相似Js
的書寫習慣,但本質上仍然是強類型,不會進行不一樣類型的自動轉換,還會說像Js
的變量嗎?
仍然以斐波那契數列爲例,Go
官網的示例中使用到的就是變量同時賦值的特性,完整代碼以下:
package main import "fmt" // fib returns a function that returns // successive Fibonacci numbers. func fib() func() int { a, b := 0, 1 return func() int { a, b = b, a+b return a } } func main() { f := fib() // Function calls are evaluated left-to-right. fmt.Println(f(), f(), f(), f(), f()) }
若是對該特性認識不夠清晰,可能以爲這並非什麼大不了的事情嘛!
實際上,俗話說,沒有對比就沒有傷害,舉一個簡單的例子: 交換變量
func TestExchange(t *testing.T) { a, b := 1, 2 t.Log(a,b) a, b = b, a t.Log(a,b) temp := a a = b b = temp t.Log(a,b) }
其餘語言中若是須要交換兩個變量,通常都是引入第三個臨時變量的寫法,而 Go
實現變量交換則很是簡單清晰,也符合人的思考而不是計算機的思考.
雖然不清楚底層會不會仍然是採用臨時變量交換,但無論怎麼說,使用該特性交換變量確實很方便!
同時對多個變量進行賦值是
Go
特有的語法,其餘語言能夠同時聲明多個變量但不能同時賦值.
const
.有些編程語言對常量和變量沒有強制規定,常量能夠邏輯上被視爲不會修改的變量,通常用全大寫字母提示用戶是常量,爲了防止常量被修改,有的編程語言可能會有額外的關鍵字進行約束.
幸運的是,Go
語言的常量提供了關鍵字 const
約束,而且禁止重複賦值,這一點很好,簡單方便.
func TestConst(t *testing.T) { const pi = 3.14 t.Log(pi) // cannot assign to pi pi = 2.828 t.Log(pi) }
除了語言層面的 const
常量關鍵字,Go
語言還要一個特殊的關鍵字 iota
,經常和常量一塊兒搭配使用!
當設置一些連續常量值或者有必定規律的常量值時,iota
能夠幫助咱們快速設置.
func TestConstForIota(t *testing.T) { const ( Mon = 1 + iota Tue Wed Thu Fri Sat Sun ) // 1 2 3 4 5 6 7 t.Log(Mon, Tue, Wed, Thu, Fri, Sat, Sun) }
大多數編程語言中,星期一表明的數字幾乎都是 0
,星期二是 1
,以此類推,致使和傳統認識上誤差,爲了校準誤差,更加符合國人習慣,所以將星期一表明的數字 0
加一,以此類推,設置初始 iota
後就能夠剩餘星期應用該規律,依次 1,2,3,4,5,6,7
若是不使用 iota
的話,可能須要手動進行連續賦值,比較繁瑣,引入了 iota
除了幫助快速設置,還能夠進行比特位級別的操做.
func TestConstForIota(t *testing.T) { const ( Readable = 1 << iota Writing Executable ) // 0001 0010 0100 即 1 2 4 t.Log(Readable, Writing, Executable) }
第一位比特位爲 1
時,表示文件可讀,第二位比特位爲 1
時,表示可寫,第三位比特位爲 1
時,表示可執行,相應的 10
進制數值依次爲 1,2,4
也就是左移一位,左移兩位,左移三位,數學上也能夠記成 2^0,2^1,2^2
.
文件的可讀,可寫,可執行三種狀態表明瞭文件的權限狀態碼,從而實現了文件的基本權限操做,常見的權限碼有 755
和 644
.
按位與 &
運算與編程語言無關,"兩位同時爲 1
時,按位與的結果才爲 1
,不然結果爲 0
",所以給定權限碼咱們能夠很方便判斷該權限是否擁有可讀,可寫,可執行等權限.
// 0111 即 7,表示可讀,可寫,可執行 accessCode := 7 t.Log(accessCode&Readable == Readable, accessCode&Writing == Writing, accessCode&Executable == Executable) // 0110 即 6,表示不可讀,可寫,可執行 accessCode = 6 t.Log(accessCode&Readable == Readable, accessCode&Writing == Writing, accessCode&Executable == Executable) // 0100 即 4,表示不可讀,不可寫,可執行 accessCode = 4 t.Log(accessCode&Readable == Readable, accessCode&Writing == Writing, accessCode&Executable == Executable) // 0000 即 0,表示不可讀,不可寫,不可執行 accessCode = 0 t.Log(accessCode&Readable == Readable, accessCode&Writing == Writing, accessCode&Executable == Executable)
accessCode&Readable
表示目標權限碼和可讀權限碼進行按位與運算,而可讀權限碼的二進制表示值爲 0001
,所以只要目標權限碼的二進制表示值第一位是 1
,按位與的結果確定是 0001
,而 0001
又恰好是可讀權限碼,因此 accessCode&Readable == Readable
爲 true
就意味着目標權限碼擁有可讀權限.
若是目標權限碼的二進制位第一個不是 1
而是 0
,則 0&1=0
,(0|1)^0=0
,因此按位與運算結果確定全是 0
即 0000
,此時 0000 == 0001
比較值 false
,也就是該權限碼不可讀.
同理可自主分析,accessCode&Writing == Writing
結果 true
則意味着可寫,不然不可寫,accessCode&Executable == Executable
結果 true
意味着可執行,false
意味着不可執行.
熟悉了 iota
的數學計算和比特位計算後,咱們趁熱打鐵,用文件大小單位繼續練習!
func TestConstForIota(t *testing.T) { const ( B = 1 << (10 * iota) Kb Mb Gb Tb Pb ) // 1 1024 1048576 1073741824 1099511627776 1125899906842624 t.Log(B, Kb, Mb, Gb, Tb, Pb) // 62.9 KB (64,411 字節) size := 64411.0 t.Log(size, size/Kb) }
字節 Byte
與 千字節 Kilobyte
之間的進制單位是 1024
,也就是 2^10
,恰好能夠用 iota
左移 10
位來表示,一次只移動一次,直接乘以 10
就行了!
怎麼樣,iota
是否是很神奇?同時是否是和我同樣也有點小困惑,iota
這貨究竟是啥?
百度翻譯給咱們的解釋是,這貨表示"微量",相似英語單詞的 little
同樣,a little
也表示"一點點".
可是 iota
除了表示一點點以外,好像還擁有自增的能力,這可不是 little
這種量詞可以傳達的意思.
所以,有可能 iota
並非原始英語含義,說不定是希臘字母的語言,查詢了標準的 24
個希臘字母表以及對應的英語註釋.
大寫 | 小寫 | 英文讀音 | 國際音標 | 意義 |
---|---|---|---|---|
Α | α | alpha | /ˈælfə/ | 角度,係數,角加速度 |
Β | β | beta | /'beitə/ | 磁通係數,角度,係數 |
Γ | γ | gamma | /'gæmə/ | 電導係數,角度,比熱容比 |
Δ | δ | delta | /'deltə/ | 變化量,屈光度,一元二次方 |
Ε | ε | epsilon | /ep'silon/ | 對數之基數,介電常數 |
Ζ | ζ | zeta | /'zi:tə/ | 係數,方位角,阻抗,相對粘度 |
Η | η | eta | /'i:tə/ | 遲滯係數,效率 |
Θ | θ | theta | /'θi:tə/ | 溫度,角度 |
Ι | ι ℩ | iota | /ai'oute/ | 微小,一點 |
Κ | κ | kappa | /'kæpə/ | 介質常數,絕熱指數 |
∧ | λ | lambda | /'læmdə/ | 波長,體積,導熱係數 |
Μ | μ | mu | /mju:/ | 磁導係數,微動摩擦系(因)數,流體動力粘度 |
Ν | ν | nu | /nju:/ | 磁阻係數,流體運動粘度,光子頻率 |
Ξ | ξ | xi | /ksi/ | 隨機數,(小)區間內的一個未知特定值 |
Ο | ο | omicron | /oumaik'rən/ | 高階無窮小函數 |
∏ | π | pi | /pai/ | 圓周率,π(n)表示不大於n的質數個數 |
Ρ | ρ | rho | /rou/ | 電阻係數,柱座標和極座標中的極徑,密度 |
∑ | σ ς | sigma | /'sigmə/ | 總和,表面密度,跨導,正應力 |
Τ | τ | tau | /tau/ | 時間常數,切應力 |
Υ | υ | upsilon | /ju:p'silən/ | 位移 |
Φ | φ | phi | /fai/ | 磁通,角,透鏡焦度,熱流量 |
Χ | χ | chi | /kai/ | 統計學中有卡方(χ2)分佈 |
Ψ | ψ | psi | /psai/ | 角速,介質電通量 |
Ω | ω | omega | /'oumigə/ | 歐姆,角速度,交流電的電角度 |
希臘字母經常用於物理,化學,生物,科學等學科,做爲常量或者變量,不一樣於通常的英語變量或常量的是,希臘字母表示的變量或常量通常具備特定的語義!
所以,iota
應該是希臘字母 I
的英語表示,該變量或者說常量表示微小,一點的含義.
翻譯成天然語言就是,這個符號表示一點點,若是表達改變的含義,那就是在原來基礎上多那麼一點點,若是表達不改變的含義,應該是隻有一點點,僅此而已.
固然,以上均是我的猜想,更加專業的說法仍是應該看下 Go
語言如何定義 iota
,按住 Ctrl
鍵,鼠標懸停在 iota
上能夠點擊進入源碼部分,以下:
// iota is a predeclared identifier representing the untyped integer ordinal // number of the current const specification in a (usually parenthesized) // const declaration. It is zero-indexed. const iota = 0 // Untyped int.
簡短翻譯:
iota
是預約義標識符,表明當前常量中無符號整型的序號,是以 0
做爲索引的.
上述註釋看起來晦澀難懂,若是是常量那就就安安靜靜當作常量,不行嗎?怎麼從常量定義中還讀出了循環變量索引的味道?
爲了驗證猜測,仍然以最簡單的星期轉換爲例,模擬每一步時的 iota
的值.
const ( // iota = 0,Mon = 1 + 0 = 1,符合輸出結果 1,此時 iota = 1,即 iota 自增1 Mon = 1 + iota // iota = 1,Tue = 1 + iota = 1 + 1 = 2,符合輸出結果 2,此時 iota = 2 Tue // iota = 2,Wed = 1 + iota = 1 + 2 = 3,符合輸出結果 3,此時 iota = 3 Wed Thu Fri Sat Sun ) // 1 2 3 4 5 6 7 t.Log(Mon, Tue, Wed, Thu, Fri, Sat, Sun)
上述猜測中將 iota
當作常量聲明循環中的變量 i
,每聲明一次,i++
,所以僅須要定義循環初始條件和循環自增變量便可完成循環賦值.
const ( Mon = 1 + iota Tue Wed Thu Fri Sat Sun ) // 1 2 3 4 5 6 7 t.Log(Mon, Tue, Wed, Thu, Fri, Sat, Sun) var days [7]int for i := 0; i < len(days); i++ { days[i] = 1 + i } // [1 2 3 4 5 6 7] t.Log(days)
這樣對應是否是以爲 iota
彷佛就是循環變量的 i
,其中 Mon = 1 + iota
就是循環初始體,Mon~Sun
有限常量就是循環的終止條件,每個常量就是下一次循環.
若是一個例子不足以驗證該猜測的話,那就再來一個!
const ( Readable = 1 << iota Writing Executable ) // 0001 0010 0100 即 1 2 4 t.Log(Readable, Writing, Executable) var access [3]int for i := 0; i < len(access); i++ { access[i] = 1 << uint(i) } // [1 2 4] t.Log(access)
上述兩個例子已經初步驗證 iota
可能和循環變量 i
具備必定的關聯性,還能夠進一步接近猜測.
const ( // iota=0 const=1+0=1 iota=0+1=1 first = 1 + iota // iota=1 const=1+1=2 iota=1+1=2 second // iota=2 const=2+2=4 iota=2+1=3 third = 2 + iota // iota=3 const=2+3=5 iota=3+1=4 forth // iota=4 const=2*4=8 iota=4+1=5 fifth = 2 * iota // iota=5 const=2*5=10 iota=5+1=6 sixth // iota=6 const=6 iota=6+1=7 seventh = iota ) // 1 2 4 5 8 10 6 t.Log(first, second, third, forth, fifth, sixth, seventh) const currentIota = iota // 0 t.Log(currentIota) var rank [7]int for i := 0; i < len(rank); i++ { if i < 2 { rank[i] = 1 + i } else if i < 4 { rank[i] = 2 + i } else if i < 6 { rank[i] = 2 * i } else { rank[i] = i } } // [1 2 3 4 5 6 7] t.Log(rank)
iota
是一組常量初始化中的循環變量索引,當這一組變量所有初始化完畢後,iota
從新開始計算,所以新的變量 currentIota
的值爲 0
而不是 7
所以,iota
經常用做一組有規律常量的初始化背後的緣由可能就是循環變量進行賦值,按照這個思路理解前面關於 iota
的例子暫時是沒有任何問題的,至於這種理解是否準確,有待繼續學習 Go
做進一步驗證,一家之言,僅供參考!
var
關鍵字聲明,常量用 const
關鍵字聲明.iota
常量進行簡化,能夠暫時理解爲採用循環方式對變量進行賦值,從而轉化成常量的初始化.斐波那契數列是一組無窮的遞增數列,形如 1,1,2,3,5,8,13...
這種從第三個數開始,後面的數老是前兩個數之和的數列就是斐波那契數列.
若是從第三個數開始考慮,那麼前兩個數就是斐波那契數列的起始值,之後的數字都符合既定規律,取前兩個數字當作變量 a,b
採用循環的方式不斷向後推動數列獲得指定長度的數列.
func TestFib(t *testing.T) { var a int = 1 var b int = 1 fmt.Print(a) for i := 0; i < 6; i++ { fmt.Print(" ", b) temp := a a = b b = temp + b } fmt.Println() }
雖然上述解法比較清晰明瞭,但還不夠簡潔,至少沒有用到 Go
語言的特性.實際上,咱們還能夠作得更好,或者說用 Go
語言的特性來實現更加清晰簡單的解法:
func TestFibSimplify(t *testing.T) { a, b := 0, 1 for i := 0; i < 6; i++ { fmt.Print(" ", b) a, b = b, a+b } fmt.Println() }
和第一種解法不一樣的是,這一次將變量 a
向前移一位,人爲製造出虛擬頭節點 0
,變量 a
的下一個節點 b
指向斐波那契數列的第一個節點 1
,隨着 a
和 b
相繼向後推動,下一個循環中的節點 b
直接符合規定,相比第一種解法縮短了一個節點.
a, b := 0, 1
是循環開始前的初始值,b
是斐波那契數列中的第一個節點,循環進行過程當中 a, b = b, a+b
語義很是清楚,節點的 a
變成節點 b
,節點 b
是 a+b
的值.
是否是很神奇,這裏既沒有用到臨時變量存儲變量 a
的值,也沒有發生變量覆蓋的狀況,直接完成了變量的交換賦值操做.
因而可知, a, b = b, a+b
並非 a=b
和 b=a+b
的執行結果的累加,而是同時完成的,這一點有些神奇,不知道 Go
是如何實現多個變量同時賦值的操做?
若是有小夥伴知道其中奧妙,還望不吝賜教,你們一塊兒學習進步!
若是你以爲上述操做有點很差理解,那麼接下來的操做,相信你必定會很熟悉,那就是兩個變量的值進行交換.
func TestExchange(t *testing.T) { a, b := 1, 2 t.Log(a, b) a, b = b, a t.Log(a, b) temp := a a = b b = temp t.Log(a, b) }
一樣的是,a, b = b, a
多變量同時賦值直接完成了變量的交換,其餘編程語言實現相似需求通常都是採用臨時變量提早存儲變量 a
的值以防止變量覆蓋,然而 Go
語言的實現方式居然和普通人的思考方式同樣,不得不說,這一點確實不錯!
經過簡單的斐波那契數列,引入了變量和常量的基本使用,以及 Go
的源碼文件相應規範,但願可以帶你入門 Go
語言的基礎,瞭解和其它編程語言有什麼不一樣以及這些不一樣之處對咱們實際編碼有什麼便捷之處,若是能用熟悉的編程語言實現 Go
語言的設計思想也不曾不是一件有意思的事情.
下面,簡單總結下本文涉及到的主要知識點,雖然是變量和常量,但重點並不在如何介紹定義上,而是側重於特殊之處以及相應的實際應用.
package main
所在的源碼文件並不必定在 main
目錄下,甚至都不必定有 main
目錄.
hello.go
源碼文件位於hello
目錄下,而hello_word.go
位於main
目錄下,可是他們所在的包都是package main
xxx_test
,測試方法命名是 TestXXX
,其中 Go
天生支持測試框架,不用額外加載第三方類庫.
var
,聲明常量的關鍵字是 const
,不管是變量仍是常量,均存在好幾種聲明方式,更是存在自動類型推斷更能夠進行簡化.
通常而言,實現其它編程語言中的全局變量聲明用var
,局部變量聲明:=
簡化形式,其中多個變量能夠進行同時賦值.
iota
來實現,能夠理解爲首次使用 iota
的常量是這組常量規律的第一個,其他的常量按照該規律依次初始化.
Go
語言沒有枚舉類,能夠用一組常量值實現枚舉,畢竟枚舉也是特殊的常量.
本文源碼已上傳到 https://github.com/snowdreams1006/learn-go 項目,感興趣的小夥伴能夠點擊查看,若是文章中有描述不當之處,懇請指出,謝謝你的評論和轉發.