一篇文章帶你了解Go語(yǔ)言基礎(chǔ)之函數(shù)(中篇)
回復(fù)“Go語(yǔ)言”即可獲贈(zèng)Python從入門(mén)到進(jìn)階共10本電子書(shū)
前言
Hey,大家好呀,我是星期八,上篇文章學(xué)了些基礎(chǔ):一篇文章帶你了解Go語(yǔ)言基礎(chǔ)之函數(shù)(上篇),這次咱們繼續(xù)學(xué)習(xí)Go基礎(chǔ)之函數(shù)進(jìn)階叭。
Go函數(shù)內(nèi)存分配圖
Go的函數(shù)內(nèi)存分配,有點(diǎn)像堆分配,有點(diǎn)像,但是本質(zhì)不是。

可以理解像堆內(nèi)存一樣,棧中保存的是堆的地址。
驗(yàn)證
代碼
package mainimport "fmt"func say() string {return "ok"}func main() {fmt.Printf("say棧上的內(nèi)容:%p\n",say)}
結(jié)果

本質(zhì)

函數(shù)的作用域
作用域這個(gè)問(wèn)題,以前可能或多或少提過(guò),再來(lái)復(fù)習(xí)一下叭。
全局變量
全局變量就是在所有函數(shù)外部定義的變量,程序不結(jié)束,變量就一直存在。
當(dāng)然,任何函數(shù)都可以訪(fǎng)問(wèn)全局變量。
注:全局變量盡量全部用大寫(xiě)。
小試牛刀
package mainimport "fmt"var NAME = "張三"func say() string {fmt.Println(NAME)return "ok"}func main() {say()fmt.Println(NAME)}
結(jié)果:

上述可能會(huì)有個(gè)問(wèn)題,全局變量,全局變量,大家共用一個(gè),要是誰(shuí)傻不拉幾修改了不就完蛋了,整個(gè)程序都涼了。
var引發(fā)的問(wèn)題
就像這樣。
package mainimport "fmt"var NAME = "張三"func say() string {fmt.Println(NAME)NAME = "李四"return "ok"}func main() {say()fmt.Println(NAME)}
結(jié)果:

這不就完?duì)僮恿藛???所以,一定要有解決辦法。
使用const解決問(wèn)題
解決辦法:使用常量定義全局變量。
package mainimport "fmt"const NAME = "張三"func say() string {fmt.Println(NAME)//NAME = "李四"http://會(huì)報(bào)錯(cuò):cannot assign to NAMEreturn "ok"}func main() {say()fmt.Println(NAME)}
總結(jié)
在定義全局變量時(shí),需要用const修飾,并且變量名全部大寫(xiě)。
局部變量
局部變量,局部變量就是在某個(gè)函數(shù)內(nèi)定義的變量,只能在自己函數(shù)內(nèi)使用。
更專(zhuān)業(yè)點(diǎn),在{}內(nèi)定義的,只能在{}內(nèi)使用,for同理。
代碼
package mainimport ("fmt")func say() string {var name = "張三"fmt.Println(name)return "ok"}func main() {say()//fmt.Println(name)//會(huì)報(bào)錯(cuò):undefined: name//for同理for i := 0; i <= 1; i++ {var c = "66"fmt.Println(c) //66}//fmt.Println(c)//會(huì)報(bào)錯(cuò):undefined: c}
defer
在Go中,defer語(yǔ)句,可以理解為在return之前執(zhí)行的一個(gè)語(yǔ)句。
如果函數(shù)沒(méi)有return,會(huì)有一個(gè)默認(rèn)的return,只是看不見(jiàn)而已。
一個(gè)defer
代碼
package mainimport "fmt"func say() {//defer盡量往前放defer fmt.Println("我是666")fmt.Println("你們都是最棒的")}func main() {say()}
執(zhí)行結(jié)果

多個(gè)defer
代碼
package mainimport "fmt"func say() {//defer盡量往前放defer fmt.Println(1)defer fmt.Println(2)defer fmt.Println(3)fmt.Println("你們都是最棒的")}func main() {say()}
執(zhí)行結(jié)果

可以發(fā)現(xiàn),defer的執(zhí)行結(jié)果是反著的。
結(jié)論:最先執(zhí)行的defer,會(huì)最后執(zhí)行,最后執(zhí)行的defer,會(huì)最先執(zhí)行,有點(diǎn)像棧,先進(jìn)后出。
defer的作用
通常來(lái)說(shuō),defer會(huì)用在釋放數(shù)據(jù)庫(kù)連接,關(guān)閉文件等需要在函數(shù)結(jié)束時(shí)處理的操作。
這里暫時(shí)先不舉例子。
panic和recover
這倆,可以理解為Python中的try和raise,因?yàn)樵贕o中,是沒(méi)有try的,是不能像其他語(yǔ)言一樣,try所有異常。
應(yīng)用場(chǎng)景:比如某個(gè)web,在啟動(dòng)時(shí),數(shù)據(jù)庫(kù)都沒(méi)連接成功,必定要啟動(dòng)失敗,就像電腦,沒(méi)有電源必不能開(kāi)機(jī)一樣。
panic
先看一下語(yǔ)法吧
package mainimport "fmt"func say() {var flag = trueif flag{//引發(fā)錯(cuò)誤,直接中斷程序的錯(cuò)誤panic("OMG,撤了撤了,必須撤了")}}func main() {say()fmt.Println("繼續(xù)呀...")//不會(huì)執(zhí)行,程序掛了}
執(zhí)行效果

可以看淡,繼續(xù)呀就沒(méi)打印,程序直接掛了,但是上述好像并沒(méi)有解決這個(gè)問(wèn)題。
recover
嘗試捕捉
代碼
package mainimport "fmt"func say() {//匿名函數(shù),defer執(zhí)行的是一個(gè)匿名函數(shù)defer func() {var err = recover()//如果有panic錯(cuò)誤,err!=nil,在此處步驟,嘗試恢復(fù)if err != nil {fmt.Println("嘗試恢復(fù)...")}}()var flag = trueif flag {panic("OMG,撤了撤了,必須撤了")}}func main() {say()fmt.Println("繼續(xù)呀...")}
執(zhí)行結(jié)果

可以看到,如果recover捕捉了,并且沒(méi)有panic,程序就會(huì)繼續(xù)正常執(zhí)行。
注意
defer必須在panic語(yǔ)句之前。
recover必須配合defer使用。
總結(jié)
上述我們學(xué)習(xí)了Go基礎(chǔ)之函數(shù)進(jìn)階。如果在操作過(guò)程中有任何問(wèn)題,記得下面討論區(qū)留言,我們看到會(huì)第一時(shí)間解決問(wèn)題。
我是碼農(nóng)星期八,如果覺(jué)得還不錯(cuò),記得動(dòng)手點(diǎn)贊一下哈。感謝你的觀看。
-------------------?End?-------------------
歡迎大家點(diǎn)贊,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群】
萬(wàn)水千山總是情,點(diǎn)個(gè)【在看】行不行
