国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

青海省高等級公路建設(shè)管理局網(wǎng)站阿里云盤資源搜索引擎

青海省高等級公路建設(shè)管理局網(wǎng)站,阿里云盤資源搜索引擎,頁面設(shè)計在哪個選項卡,蕪湖市建設(shè)廳網(wǎng)站引言 程序遇到的錯誤大致分為兩類:程序員預(yù)料到的錯誤和程序員沒有預(yù)料到的錯誤。我們在前兩篇關(guān)于[錯誤處理]的文章中介紹的error接口主要處理我們在編寫Go程序時預(yù)期的錯誤。error接口甚至允許我們承認(rèn)函數(shù)調(diào)用發(fā)生錯誤的罕見可能性,因此我們可以在這些情況下進(jìn)行…

引言

程序遇到的錯誤大致分為兩類:程序員預(yù)料到的錯誤和程序員沒有預(yù)料到的錯誤。我們在前兩篇關(guān)于[錯誤處理]的文章中介紹的error接口主要處理我們在編寫Go程序時預(yù)期的錯誤。error接口甚至允許我們承認(rèn)函數(shù)調(diào)用發(fā)生錯誤的罕見可能性,因此我們可以在這些情況下進(jìn)行適當(dāng)?shù)捻憫?yīng)。

異常屬于第二類錯誤,是程序員沒有預(yù)料到的。這些不可預(yù)見的錯誤會導(dǎo)致程序自動終止并退出正在運行的Go程序。常見的錯誤往往會造成異常。在本教程中,我們將研究Go中常見操作可能產(chǎn)生嚴(yán)重錯誤的幾種方式,我們還將了解避免這些嚴(yán)重錯誤的方法。我們還將使用[defer]語句和recover函數(shù)來捕獲錯誤,以免它們意外地終止我們正在運行的Go程序。

理解異常

Go中的某些操作會自動返回異常并停止程序。常見的操作包括超出[array]容量的索引、執(zhí)行類型斷言、調(diào)用nil指針的方法、錯誤地使用互斥量以及嘗試使用閉合通道。這些情況大多是由編程時犯的錯誤導(dǎo)致的,而編譯器在編譯程序時無法檢測到這些錯誤。

由于異常包含對解決問題有用的細(xì)節(jié),開發(fā)人員通常將異常用作在程序開發(fā)過程中犯了錯誤的指示。

出界異常

當(dāng)您試圖訪問超出切片長度或數(shù)組容量的索引時,Go運行時將生成一個異常。

下面的例子犯了一個常見的錯誤,即試圖使用內(nèi)置函數(shù)len返回的切片長度來訪問切片的最后一個元素。試著運行這段代碼,看看為什么會產(chǎn)生異常:

package mainimport ("fmt"
)func main() {names := []string{"lobster","sea urchin","sea cucumber",}fmt.Println("My favorite sea creature is:", names[len(names)])
}
Outputpanic: runtime error: index out of range [3] with length 3goroutine 1 [running]:
main.main()/tmp/sandbox879828148/prog.go:13 +0x20

異常的輸出名稱提供了一個提示:panic: runtime error: index out of range。我們制作了一個有三個海洋生物的切片。然后,我們嘗試使用內(nèi)置函數(shù)len將切片的長度作為索引來獲取切片的最后一個元素。別忘了,切片和數(shù)組是從0開始的;所以這個切片的第一個元素是0,最后一個元素的索引是2。由于我們試圖在第三個索引3處訪問切片,因此切片中沒有可以返回的元素,因為它超出了切片的邊界。運行時別無選擇,只能終止和退出,因為我們要求它做一些不可能的事情。Go也無法在編譯期間證明此代碼將嘗試執(zhí)行此操作,因此編譯器無法捕獲此操作。

還要注意,后續(xù)的代碼沒有運行。這是因為異常是一個會完全停止Go程序執(zhí)行的事件。生成的消息包含多種有助于診斷異常原因的信息。

異常的剖析

嚴(yán)重錯誤由指示嚴(yán)重錯誤原因的消息和堆棧跟蹤組成,后者可以幫助您定位代碼中產(chǎn)生嚴(yán)重錯誤的位置。

任何異常的第一部分都是信息。它總是以字符串panic:開始,后面跟著一個根據(jù)異常原因而變化的字符串。上一個練習(xí)中的異常語句包含如下消息:

panic: runtime error: index out of range [3] with length 3

panic:前綴后面的字符串runtime error:告訴我們,異常是由語言運行時生成的。這個錯誤告訴我們,我們試圖使用的索引[3]超出了切片長度3的范圍。

此消息之后是堆棧跟蹤。堆棧跟蹤形成了一個map,我們可以根據(jù)它準(zhǔn)確定位生成異常時正在執(zhí)行的代碼行,以及之前的代碼如何調(diào)用該代碼。

goroutine 1 [running]:
main.main()/tmp/sandbox879828148/prog.go:13 +0x20

前面例子中的堆棧跟蹤顯示,我們的程序從第13行文件/tmp/sandbox879828148/prog.go中生成了異常。它還告訴我們,此異常是在main包中的main()函數(shù)中生成的。

堆棧跟蹤被分成多個獨立的塊——一個用于程序中的每個goroutine。每個Go程序的執(zhí)行都是由一個或多個goroutines完成的,這些goroutines可以獨立和同時執(zhí)行Go代碼的部分內(nèi)容。每個塊都以goroutine X [state]:開頭。header給出了goroutine的ID號以及發(fā)生異常時它所處的狀態(tài)。在header之后,堆棧跟蹤顯示了發(fā)生嚴(yán)重錯誤時程序正在執(zhí)行的函數(shù),以及該函數(shù)執(zhí)行的文件名和行號。

前面例子中的異常是由對切片的越界訪問產(chǎn)生的。當(dāng)對未設(shè)置的指針調(diào)用方法時,也可能產(chǎn)生異常。

Nil接收器

Go編程語言有指針,指向運行時存在于計算機內(nèi)存中的某種類型的特定實例。指針可以假定值為nil,表示它們不指向任何東西。當(dāng)我們試圖在一個為nil的指針上調(diào)用方法時,Go運行時將生成一個異常。類似地,接口類型的變量在被方法調(diào)用時也會產(chǎn)生錯誤。要查看在這些情況下產(chǎn)生的嚴(yán)重錯誤,請嘗試以下示例:

package mainimport ("fmt"
)type Shark struct {Name string
}func (s *Shark) SayHello() {fmt.Println("Hi! My name is", s.Name)
}func main() {s := &Shark{"Sammy"}s = nils.SayHello()
}
Outputpanic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xdfebagoroutine 1 [running]:
main.(*Shark).SayHello(...)/tmp/sandbox160713813/prog.go:12
main.main()/tmp/sandbox160713813/prog.go:18 +0x1a

在這個例子中,我們定義了一個名為Shark的結(jié)構(gòu)體。Shark在它的指針接收器上定義了一個名為SayHello的方法,當(dāng)被調(diào)用時,它會向標(biāo)準(zhǔn)輸出打印一條問候語。在我們的main函數(shù)體內(nèi),我們創(chuàng)建了這個Shark結(jié)構(gòu)體的一個新實例,并使用&操作符請求一個指向它的指針。這個指針被賦值給s變量。然后我們使用s = nil語句將s變量重新賦值為nil。最后,我們嘗試在變量s上調(diào)用SayHello方法。我們沒有收到來自Sammy的友好消息,而是收到了一個警告,表示我們試圖訪問一個無效的內(nèi)存地址。因為s變量是nil,當(dāng)調(diào)用SayHello函數(shù)時,它嘗試訪問*Shark類型的字段Name。因為這是一個指針接收器,在這個例子中接收器是nil,它無法解引nil指針,所以出現(xiàn)了問題。

雖然我們在這個例子中顯式地將s設(shè)置為nil,但實際上這種情況并不明顯。當(dāng)你看到涉及nil pointer dereference的嚴(yán)重錯誤時,請確保你已經(jīng)正確地為任何你可能創(chuàng)建的指針變量賦值。

由nil指針產(chǎn)生的嚴(yán)重錯誤和越界訪問是運行時產(chǎn)生的兩種常見嚴(yán)重錯誤。也可以使用內(nèi)置函數(shù)手動生成異常。

使用內(nèi)置函數(shù)panic

我們也可以使用內(nèi)置函數(shù)panic來生成我們自己的異常。它接受一個字符串作為參數(shù),即異常將產(chǎn)生的消息。通常,這條消息比重寫代碼返回錯誤要簡潔。此外,我們可以在我們自己的包中使用它,以表明開發(fā)人員在使用我們的包的代碼時可能犯了錯誤。只要有可能,最佳實踐是嘗試向我們的包的使用者返回error值。

運行以下代碼,查看從另一個函數(shù)調(diào)用的函數(shù)中生成的異常:

package mainfunc main() {foo()
}func foo() {panic("oh no!")
}
Outputpanic: oh no!goroutine 1 [running]:
main.foo(...)/tmp/sandbox494710869/prog.go:8
main.main()/tmp/sandbox494710869/prog.go:4 +0x40

在這里,我們定義了一個函數(shù)foo,它使用字符串"oh no!"調(diào)用內(nèi)置的panic。這個函數(shù)被我們的main函數(shù)調(diào)用。注意輸出的信息panic: oh no!,堆棧跟蹤顯示了一個單獨的goroutine,其中有兩行代碼:一行用于main()函數(shù),另一行用于我們的foo()函數(shù)。

我們已經(jīng)看到,異常似乎會在產(chǎn)生它們的地方終止程序。當(dāng)需要關(guān)閉開放資源時,這可能會產(chǎn)生問題。Go提供了一種始終執(zhí)行某些代碼的機制,即使在出現(xiàn)緊急情況時也是如此。

延遲函數(shù)

你的程序可能有必須正確清理的資源,即使在運行時處理異常時也是如此。Go允許您推遲函數(shù)調(diào)用的執(zhí)行,直到調(diào)用它的函數(shù)完成執(zhí)行。延遲函數(shù)即使在緊急情況下也會運行,它被用作一種安全機制,以防范緊急情況帶來的混亂。通過像往常一樣調(diào)用函數(shù),然后用defer關(guān)鍵字前綴整個語句來延遲函數(shù),就像defer sayHello()一樣。運行下面的例子,看看在發(fā)生異常事件時如何打印消息:

package mainimport "fmt"func main() {defer func() {fmt.Println("hello from the deferred function!")}()panic("oh no!")
}
Outputhello from the deferred function!
panic: oh no!goroutine 1 [running]:
main.main()/Users/gopherguides/learn/src/github.com/gopherguides/learn//handle-panics/src/main.go:10 +0x55

在這個例子中的main函數(shù)中,我們首先defer了對一個匿名函數(shù)的調(diào)用,該匿名函數(shù)會打印出消息"hello from the deferred function!"。然后main函數(shù)立即使用panic函數(shù)產(chǎn)生一個異常。在這個程序的輸出中,我們首先看到deferred函數(shù)被執(zhí)行了,并打印了它的消息。接下來是我們在main中生成的異常。

延遲函數(shù)可以防止意外情況的發(fā)生。在延遲函數(shù)中,Go還為我們提供了使用另一個內(nèi)置函數(shù)阻止異常終止我們的Go程序的機會。

處理異常

異常只有一個恢復(fù)機制——內(nèi)置函數(shù)recover。這個函數(shù)允許你在異常通過調(diào)用棧的過程中攔截它,防止它意外地終止你的程序。它有嚴(yán)格的使用規(guī)則,但在生產(chǎn)應(yīng)用程序中可能是非常寶貴的。

由于它是builtin包的一部分,因此可以在不導(dǎo)入任何其他包的情況下調(diào)用recover:

package mainimport ("fmt""log"
)func main() {divideByZero()fmt.Println("we survived dividing by zero!")}func divideByZero() {defer func() {if err := recover(); err != nil {log.Println("panic occurred:", err)}}()fmt.Println(divide(1, 0))
}func divide(a, b int) int {return a / b
}
Output2009/11/10 23:00:00 panic occurred: runtime error: integer divide by zero
we survived dividing by zero!

在這個例子中,我們的main函數(shù)調(diào)用了我們定義的函數(shù)divideByZero。在這個函數(shù)中,我們defer調(diào)用一個匿名函數(shù),該函數(shù)負(fù)責(zé)處理在執(zhí)行divideByZero時可能出現(xiàn)的任何錯誤。在這個延遲匿名函數(shù)中,我們調(diào)用recover內(nèi)置函數(shù),并將它返回的錯誤賦值給一個變量。如果divideByZero處于異常狀態(tài),這個error值將被設(shè)置,否則它將是nil。通過比較err變量和nil變量,我們可以檢測是否發(fā)生了異常,在這種情況下,我們使用log.Println函數(shù)記錄異常,就像它是其他任何error一樣。

在這個延遲匿名函數(shù)之后,我們調(diào)用另一個我們定義的函數(shù)divide,并嘗試使用fmt.Println打印它的結(jié)果。提供的參數(shù)將導(dǎo)致divide執(zhí)行除數(shù)為0的運算,這將產(chǎn)生一個異常。

在這個示例的輸出中,我們首先看到恢復(fù)panic的匿名函數(shù)的日志消息,然后是消息 we survived dividing by zero!。我們確實做到了這一點,感謝內(nèi)置函數(shù)recover阻止了將終止我們的Go程序的災(zāi)難性異常。

recover()返回的err值正好是調(diào)用panic()時提供的值。因此,當(dāng)異常沒有發(fā)生時,確保err值僅為nil至關(guān)重要。

recover檢測異常

recover函數(shù)依賴于錯誤的值來確定是否發(fā)生了嚴(yán)重錯誤。因為panic函數(shù)的參數(shù)是一個空接口,所以它可以是任何類型。任何接口類型的0值,包括空接口,都是nil。必須注意避免將nil作為panic的參數(shù),如下例所示:

package mainimport ("fmt""log"
)func main() {divideByZero()fmt.Println("we survived dividing by zero!")}func divideByZero() {defer func() {if err := recover(); err != nil {log.Println("panic occurred:", err)}}()fmt.Println(divide(1, 0))
}func divide(a, b int) int {if b == 0 {panic(nil)}return a / b
}```go```shell
Outputwe survived dividing by zero!

這個例子與前面的例子相同,涉及到recover,只是做了一些細(xì)微的修改。divide函數(shù)被修改為檢查它的除數(shù)b是否等于0。如果是,它將使用內(nèi)置的panic并傳入nil參數(shù)來生成一個異常。這一次的輸出不包括顯示發(fā)生了嚴(yán)重錯誤的日志消息,即使divide創(chuàng)建了一個嚴(yán)重錯誤。這種靜默行為就是為什么確保panic內(nèi)置函數(shù)的參數(shù)不是nil非常重要的原因。

總結(jié)

我們已經(jīng)看到了Go中創(chuàng)建panic的多種方式,以及如何使用內(nèi)置的recover恢復(fù)它們。雖然您自己可能不需要使用panic,但從panic中正確恢復(fù)是使Go應(yīng)用程序可用于生產(chǎn)的重要步驟。

http://aloenet.com.cn/news/38244.html

相關(guān)文章:

  • 網(wǎng)站建設(shè)策劃方案ppt顧問式營銷
  • wordpress修改注冊表班級優(yōu)化大師學(xué)生版
  • 做網(wǎng)絡(luò) 批發(fā)的網(wǎng)站seo運營推廣
  • 安卓網(wǎng)站開發(fā)平臺東莞百度seo電話
  • 網(wǎng)站開發(fā)主要用什么語言武漢seo關(guān)鍵詞排名優(yōu)化
  • 服務(wù)器 無法訪問網(wǎng)站上海網(wǎng)絡(luò)推廣外包公司
  • 深圳建筑工程招聘信息凱里seo排名優(yōu)化
  • 最好的自助建站系統(tǒng)店鋪運營方案策劃
  • 網(wǎng)站建設(shè)開發(fā)的條件軟文營銷實施背景
  • 在北京做網(wǎng)站制作一個月多少錢百度快照收錄入口
  • 東莞汽車網(wǎng)站建設(shè)百度指數(shù)排名
  • 網(wǎng)站建設(shè)實力滴滴友鏈
  • 深圳市招聘信息網(wǎng)站佛山網(wǎng)絡(luò)排名優(yōu)化
  • 網(wǎng)站建設(shè)包含哪些方面刷關(guān)鍵詞排名軟件有用嗎
  • 深度網(wǎng)營銷型網(wǎng)站建設(shè)公司怎么樣seo網(wǎng)站優(yōu)化
  • 東莞網(wǎng)站設(shè)計電話網(wǎng)址查詢服務(wù)中心
  • 重慶廣告網(wǎng)站推廣seo結(jié)算系統(tǒng)
  • 高端網(wǎng)站建設(shè)公司價格關(guān)鍵詞優(yōu)化價格
  • 免費咨詢律師不收費的平臺長治seo顧問
  • 阿里巴巴招聘官網(wǎng)西安關(guān)鍵詞優(yōu)化平臺
  • 做特殊單頁的網(wǎng)站怎樣建立一個網(wǎng)絡(luò)銷售平臺
  • 自己做靜態(tài)網(wǎng)站的步驟百度搜索技巧
  • 建站寶盒做的網(wǎng)站十大免費excel網(wǎng)站
  • 公司做網(wǎng)站之前要準(zhǔn)備什么軟件廣點通廣告投放平臺登錄
  • 什么網(wǎng)站做電氣自動化兼職做優(yōu)化的網(wǎng)站
  • 做博物館網(wǎng)站最重要性seo視頻教學(xué)網(wǎng)站
  • 深圳做網(wǎng)站有哪些指數(shù)函數(shù)
  • 設(shè)計師做網(wǎng)站的流程西安網(wǎng)站建設(shè)哪家好
  • 怎么設(shè)計自己的網(wǎng)站知乎小說推廣對接平臺
  • 專業(yè)汽車網(wǎng)站seo日常工作都做什么的