現在這個系列,已經開始兩極分化了。 點贊的認為風格輕松,看着不困。反之,就有人嫌寫的羅里吧嗦,上綱上線。所以善意提醒,里面不只是技術語言,還有段子。專心看技術的,千萬別點!別怪我沒提醒!差點忘說,版權沒有,轉載隨意,別刪郵箱(ztao8607@gmail.com)
我都承認文章標題起的是越來越扯淡了。從開始的"安裝Golang","解密Golang工程結構"這一類中規中矩的標題,現在已經慢慢進化成了"維多利亞的秘密","我們是80后"這一類相當無技術含義的標題。說實話,我都快編不下去了。
來一段歌詞,看能否勾起你的回憶:
敢在景陽崗上穿虎皮裝。 在高粱地里套母狼。左手拿刀(挲),右手拿槍(啪)。他就是蟑螂中的絕對偶像。敢去皇宮里翻遍御膳房。也能到你家里去掃盪。就算鞋板兒拍下敵敵畏奪命。死也要死個酷了斃。
早上無意聽到這段<特務小強>的歌詞,感覺一下就回到了上大學的那個時光。 不知道即將步入青年后半段的人,是不是都喜歡懷舊。我的80后記憶還停留在老北京酸奶,北京方便面,鐳射錄像廳,世嘉游戲機。除了二八大杠的自行車,就是路邊的游戲機房。 那會的網吧還都是局域網在玩紅警,CS剛出來名稱換做反恐精英。沙丘還能找到,但玩最多的當屬金庸群俠傳。
就是在這些游戲當中,讓我對計算機充滿了好奇,也憧憬着如果有一天我能自己寫個游戲該有多好。理想一直存在,可現實已被摧殘。看着身邊的90后,00后已經逐漸扛起行業的大梁,只能對着他們感嘆一句:
在青年的隊列里面,我們已經排在了隊尾。好好干,總有一天,讓我們在隊尾匯合。
感慨已完,開始正題。在維密一節中,我們講到了函數的使用方式,本節聊一聊變量作用域的事情。
變量作用域
綜合之前的描述,我們可以得出一個結論:任何一種語言,都存在變量。 並由此可知,只要有變量,就會有變量作用域。 好比每個國家都有法律,而每個法律都有適用范圍。最簡單的例子就是中國法律管不了美國的事。所以本節聊的就是變量作用域的那些事。
在Golang當中,變量分為三類:
- 本地局部變量
- 全局變量
- 參數變量
本地局部變量,顧名思義只能在本地生效的變量。在Golang當中,本地的定義是按照函數或者語義塊來區分的。只要在一個函數中定義的變量,或者在一個語義塊中定義的變量都是本地變量。
函數定義容易理解,例如下面的例子:
func Test(){
str := "This is a local var"
....
}
str是定義在Test函數內部的變量,因此就是本地變量。下面則是一個語義塊的示例:
func Test(){
for{
str := "This is a local var in block"
...
}
}
可以看到str是定義在for這個語義塊內部的,因此str也是一個本地變量。 那么本地變量的作用域在哪里呢? 哪國的法律管哪國的事,變量定義在哪里,就在當前范圍內生效。
在示例一中,str定義在Test函數中,因此在Test函數內部,str都暢通無阻。出了Test函數以后,就無法使用str變量了。 同理可知,在示例二中,str定義在for循環內部,因此只能在for內部使用str。一旦出了for循環,同樣也無法再訪問str。
是的,你一定會問,如果出現重名變量怎么辦? 首先我建議,盡量不要出現重名。 盡量不要自己給自己挖坑。 但非挖不可,那Golang會按照當前作用域優先的原則,替換變量。例如下面的例子:
package main
import (
"fmt"
)
func main() {
str := "local var"
if true {
str := "block var"
fmt.Println(str)
}
fmt.Println(str)
}
在main函數中定義了一個str變量,然后再if語義塊中也定義了一個str變量。按照當前作用域優先的原則,當程序運行到if內部之后,if中的str會替代外部的str變量值。 所以首先輸出"block var'。 當出了if范圍之后,里面的str已經失效,外部無法訪問。因此最后會使用main函數作用域的str變量,所以輸出"local var"。
因此最終輸出
block var
local var
還是那句話,代碼最好別用花哨的東西,寫的清清楚楚明明白白最好。一般別挖坑,要挖就挖大坑。
與本地變量相對應的就是全局變量。 只要是在函數外部定義的都屬於全局變量。例如下面的例子:
var g int
func main(){
a := 10
b := 10
g = a+b
...
}
注意千萬不能g := a+b。 因為我們說過變量的聲明方式有“var"和”:="兩種。如果不小心寫了個" g:=a+b"。雖然對最終的結果沒有影響,但意思已經改變了,變成了在main函數中重新創建了一個g變量。
雖說全局變量也是變量,但全局變量的聲明只能通過var來實現。例如下面是合法的:
var g int
或者
var g = 40
func main(){
...
}
而下面則是非法的:
g := 40
func main(){
}
不要問什么了,規定就是規定,遵守就好。全局變量的作用域當然就是全局了,但這個全局指的是package內。 在當前package內都可以隨意訪問,如果想讓其他package訪問,那么需要遵從Golang的原則,首字母大寫。這樣才能讓其他Package訪問到。
如果遇到同名問題怎么樣? Golang同樣會按照作用域優先原則處理,例如下面的例子:
var g = 40
func main(){
a := 10
b := 10
g := a+b
...
}
注意,在main函數中,同樣存在一個g變量,但這個g變量是通過":="聲明出來的。 因此按照作用域優先原則,此時此刻的g=30。全局的g=40。 如果這方面感覺不理解,寫兩句代碼,run一下立馬見分曉。
最后一種是參數變量。參數變量是一種特殊的變量,既不屬於本地變量,也不屬於全局變量(有點廢話了,如果屬於就不會單列出來了)。 其介於兩者之間,作用域是函數范圍,先看下面的例子:
func Test(str string){
i := 10
....
}
通過上面的分析可知,i屬於本地變量,而str則屬於參數變量。 與本地變量相同的一點時,其作用域相同,都是函數范圍。 但不同的地方有兩處:
- 參數變量賦值是在外部完成的,聯想一下<維密>那節,我們講解函數時,如何給參數賦值。就可以知道賦值的動作是在調用時完成的。
- 參數變量可以聲明之后不使用。這點尤為明顯,如果聲明了一個本地變量,但自始至終都沒有用到。編譯時會提示刪除這個變量。而參數變量,無論函數內部有沒有用到,都不會提示。
所以可以向對待本地局部變量那樣對待參數變量,本地局部變量適用的法則,參數變量同樣適用。
寫完變量,看了看內容不多。因此再多寫一點,反正沒有出版社約稿,也就不會受到大綱的約束,想到哪里寫到哪里。
下面進入Golang常用類型的使用場景
String
在每種編程開發語言種,字符串都是內置的一種數據類型,原因就是因為它太重要了。前面也提到過一嘴,Golang的字符串本質是字符數組([]byte)。
創建字符串很簡單,上面用過很多次了:
var greeting = "Hello world!"
或者
greeting := "Hello world!"
Golang默認使用UTF-8編碼處理字符串,所以不用擔心漢字編碼的問題。作為一種現代語言,Golang不限制字符串的長度,理論上只要內存有多大,字符串就可以有多大。但還是本着"no zuo no die"的理念,別放那么長的字符串,沒人喜歡在代碼中讀小說。
Golang專門有一個strings的package(https://golang.org/pkg/strings/ )來處理各種常見的string問題。例如查找,拼接,判斷,大小寫轉換和替換,拷貝等等常見功能。
String很重要,但真的沒什么可講的。絕大多數的問題都可以通過strings庫來解決,如果有問題,自行看一下庫文檔吧。 雖說是本系列是個入門教程,但事無巨細都寫完,很不現實。 如果寫完了,那就變成Golang中文文檔了。
所以String這一小節,記住有一個strings庫就夠了。
如果你是80后,真心感嘆你還能有如此強的求知欲。 如果你非80后,好好珍惜眼前的日子吧。 該玩就玩,該揮霍就揮霍。別等哪天將發際線熬到了耳后,才后悔當初沒有好好泡妹子。