“區塊鏈+時代無疑會是下一個風口,然而現在的區塊鏈行業專業型人才正在遭遇瓶頸”兄弟連教育區塊鏈學院院長尹成表示,“希望能通過兄弟連教育區塊鏈培訓學院為社會為企業培養並輸送更多優質的區塊鏈高精尖型技術人才。
Go語言中的閉包同樣也會引用到函數外的變數。閉包的實現確保只要閉包還被使用,那麼
被閉包引用的變數會一直存在,例如:package main
import "fmt"
func main(){
var j int = 5
a := func()(func()) { //圓括弧中的func()表示傳回值是一個func()函數
var i int = 10
return func() { //這裡返回一個匿名函數
fmt.Printf("i, j: %v, %v\n", i, j)
}
}() //花括弧後帶參數列表表示調用匿名函數,執行到這裡變數a就等於了一個函數了.
a() //調用函數a
j *= 2 //修改函數外部的變數j
a() //再次調用函數a
}
運行結果:
i, j: 10, 5
i, j: 10, 10
在上面的例子中,變數 a 指向的閉包函數引用了局部變數 i 和 j , i 的值被隔離,在閉包外不能被修改,改變 j 的值以後,再次調用 a ,發現結果是修改過的值。在變數 a 指向的閉包函數中,只有內部的匿名函數才能訪問變數 i ,而無法通過其他途徑訪問到,因此保證了 i 的安全性。
2.錯誤處理
2.1 error介面
Go語言引入了一個關於錯誤處理的標準模式,即 error 介面,該介面的定義如下:
type error interface {
Error() string
}
建立error通常如下:
var e error = errors.New("...")//需要使用使用errors包
對於大多數函數,如果要返回錯誤,大致上都可以定義為如下模式,將 error 作為多種返回
值中的最後一個,但這並非是強制要求:
func Foo(param int)(res int,err error){
//....
}
調用時的代碼建議按如下方式處理錯誤情況:
1
2
n, err := Foo(0)
if err != nil {
// 錯誤處理
} else {
// 使用傳回值n
}
2.2 defer關鍵字
Go語言中有種不錯的設計,即延遲(defer)語句,你可以在函數中添加多個defer語句。當函數執行到最後時,這些defer語句會按照逆序執行,最後該函數返回。特別是當你在進行一些開啟資源的操作時,遇到錯誤需要提前返回,在返回前你需要關閉相應的資源,不然很容易造成資源流失等問題。
func ReadWrite() bool {
file.Open("file")
// 做一些工作
if failureX {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
}
我們看到上面有很多重複的代碼,Go的defer有效解決了這個問題。使用它後,不但代碼量減少了很多,而且程式變得更優雅。
func ReadWrite() bool {
file.Open("file")
defer file.Close() //保證資源正常關閉
if failureX {
return false
}
if failureY {
return false
}
return true
}
如果有很多調用defer,那麼defer是採用後進先出模式
1
2
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i) //輸出結果:4 3 2 1 0
}
defer有點類似java中的try{}finall{}
2.3 panic和recover函數
Go語言有2個內建的函數panic()和recover(),用以報告和捕獲運行時發生的程式錯誤,與error不同,panic和recover一般用在函數內部。一定要注意不要濫用panic和recover,可能會導致效能問題,一般只在未知輸入和不可靠請求時使用。Go語言的錯誤處理流程:當一個函數在執行過程中出現了異常或遇到 panic(),正常語句就會立即終止,然後執行 defer 語句,再報告異常資訊,最後退出 goroutine。如果在defer中使用了recover()函數,則會捕獲錯誤資訊,使該錯誤資訊終止報告。如下樣本,例子來自網路
package main
import (
"log" //log包
"strconv" //字元轉換包
)
//捕獲因未知輸入導致的程式異常
func catch(nums ...int) int {
defer func() {
//recover()可以捕獲運行時發生的異常,避免異常時程式直接over,通常用在defer函數內
if r := recover(); r != nil {
log.Println("[E]", r) //將捕獲的異常資訊通過log列印,而不會導致程式掛掉
}
}()
return nums[1] * nums[2] * nums[3] //index out of range
}
//主動拋出 panic,不推薦使用,可能會導致效能問題
func toFloat64(num string) (float64, error) {
defer func() {
if r := recover(); r != nil {
log.Println("[W]", r)
}
}()
if num == "" {
panic("param is null") //主動拋出 panic
}
return strconv.ParseFloat(num, 10)
}
func main() {
catch(2, 8)
toFloat64("")
}
運行結果:
2016/03/26 20:16:03 [E] runtime error: index out of range
2016/03/26 20:16:03 [W] param is null
最後補充下nil的介紹:
golang的nil在概念上和其它語言的null、None、nil、NULL一樣,都指代零值或空值。
nil是預先說明的標識符,也即通常意義上的關鍵字。在golang中,nil只能賦值給指標、
channel、func、interface、map或slice類型的變數。如果未遵循這個規則,則會引發panic。
高能預警,兄弟連教育區塊鏈直播課程8月持續火爆來襲!
原價1188元的12節區塊鏈進階課程,現僅需1元!
還可免費領取《Go語言基礎實戰項目開發》與《Go語言進階實戰項目開發》教材兩本!!
限時限量!!先到先得!!
http://www.ydma.cn/open/course/24