一篇文章帶你瞭解 Go 語言基礎之函數(中篇)
前言
Hey,大家好呀,我是星期八,上篇文章學了些基礎:一篇文章帶你瞭解 Go 語言基礎之函數(上篇),這次咱們繼續學習 Go 基礎之函數進階叭。
Go 函數內存分配圖
Go 的函數內存分配,有點像堆分配,有點像,但是本質不是。
可以理解像堆內存一樣,棧中保存的是堆的地址。
驗證
代碼
package main
import "fmt"
func say() string {
return "ok"
}
func main() {
fmt.Printf("say棧上的內容:%p\n",say)
}
結果
本質
函數的作用域
作用域這個問題,以前可能或多或少提過,再來複習一下叭。
全局變量
全局變量就是在所有函數外部定義的變量,程序不結束,變量就一直存在。
當然,任何函數都可以訪問全局變量。
注: 全局變量儘量全部用大寫。
小試牛刀
package main
import "fmt"
var NAME = "張三"
func say() string {
fmt.Println(NAME)
return "ok"
}
func main() {
say()
fmt.Println(NAME)
}
結果:
上述可能會有個問題,全局變量,全局變量,大家共用一個,要是誰傻不拉幾修改了不就完蛋了,整個程序都涼了。
var 引發的問題
就像這樣。
package main
import "fmt"
var NAME = "張三"
func say() string {
fmt.Println(NAME)
NAME = "李四"
return "ok"
}
func main() {
say()
fmt.Println(NAME)
}
結果:
這不就完犢子了嗎??? 所以,一定要有解決辦法。
使用 const 解決問題
解決辦法: 使用常量定義全局變量。
package main
import "fmt"
const NAME = "張三"
func say() string {
fmt.Println(NAME)
//NAME = "李四"//會報錯:cannot assign to NAME
return "ok"
}
func main() {
say()
fmt.Println(NAME)
}
總結
在定義全局變量時,需要用const
修飾,並且變量名全部大寫。
局部變量
局部變量,局部變量就是在某個函數內定義的變量,只能在自己函數內使用。
更專業點,在{}
內定義的,只能在{}
內使用,for
同理。
代碼
package main
import (
"fmt"
)
func say() string {
var name = "張三"
fmt.Println(name)
return "ok"
}
func main() {
say()
//fmt.Println(name)//會報錯:undefined: name
//for同理
for i := 0; i <= 1; i++ {
var c = "66"
fmt.Println(c) //66
}
//fmt.Println(c)//會報錯:undefined: c
}
defer
在 Go 中,defer
語句,可以理解爲在return
之前執行的一個語句。
如果函數沒有return
,會有一個默認的return
,只是看不見而已。
一個 defer
代碼
package main
import "fmt"
func say() {
//defer儘量往前放
defer fmt.Println("我是666")
fmt.Println("你們都是最棒的")
}
func main() {
say()
}
執行結果
多個 defer
代碼
package main
import "fmt"
func say() {
//defer儘量往前放
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("你們都是最棒的")
}
func main() {
say()
}
執行結果
可以發現,defer 的執行結果是反着的。
結論: 最先執行的 defer,會最後執行,最後執行的 defer,會最先執行,有點像棧,先進後出。
defer 的作用
通常來說,defer 會用在釋放數據庫連接,關閉文件等需要在函數結束時處理的操作。
這裏暫時先不舉例子。
panic 和 recover
這倆,可以理解爲 Python 中的try
和raise
,因爲在 Go 中,是沒有try
的,是不能像其他語言一樣,try
所有異常。
應用場景: 比如某個 web,在啓動時,數據庫都沒連接成功,必定要啓動失敗,就像電腦,沒有電源必不能開機一樣。
panic
先看一下語法吧
package main
import "fmt"
func say() {
var flag = true
if flag{
//引發錯誤,直接中斷程序的錯誤
panic("OMG,撤了撤了,必須撤了")
}
}
func main() {
say()
fmt.Println("繼續呀...")//不會執行,程序掛了
}
執行效果
可以看淡,繼續呀
就沒打印,程序直接掛了,但是上述好像並沒有解決這個問題。
recover
嘗試捕捉
代碼
package main
import "fmt"
func say() {
//匿名函數,defer執行的是一個匿名函數
defer func() {
var err = recover()
//如果有panic錯誤,err!=nil,在此處步驟,嘗試恢復
if err != nil {
fmt.Println("嘗試恢復...")
}
}()
var flag = true
if flag {
panic("OMG,撤了撤了,必須撤了")
}
}
func main() {
say()
fmt.Println("繼續呀...")
}
執行結果
可以看到,如果 recover 捕捉了,並且沒有panic
,程序就會繼續正常執行。
注意
defer
必須在panic
語句之前。
recover
必須配合defer
使用。
總結
上述我們學習了 Go 基礎之函數進階。如果在操作過程中有任何問題,記得下面討論區留言,我們看到會第一時間解決問題。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/obQsFaTvrqijbUEOteVmQA