中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

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

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

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

引言

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

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

理解異常

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

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

出界異常

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

下面的例子犯了一個(gè)常見的錯(cuò)誤,即試圖使用內(nèi)置函數(shù)len返回的切片長度來訪問切片的最后一個(gè)元素。試著運(yùn)行這段代碼,看看為什么會產(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

異常的輸出名稱提供了一個(gè)提示:panic: runtime error: index out of range。我們制作了一個(gè)有三個(gè)海洋生物的切片。然后,我們嘗試使用內(nèi)置函數(shù)len將切片的長度作為索引來獲取切片的最后一個(gè)元素。別忘了,切片和數(shù)組是從0開始的;所以這個(gè)切片的第一個(gè)元素是0,最后一個(gè)元素的索引是2。由于我們試圖在第三個(gè)索引3處訪問切片,因此切片中沒有可以返回的元素,因?yàn)樗隽饲衅倪吔?。運(yùn)行時(shí)別無選擇,只能終止和退出,因?yàn)槲覀円笏鲆恍┎豢赡艿氖虑椤o也無法在編譯期間證明此代碼將嘗試執(zhí)行此操作,因此編譯器無法捕獲此操作。

還要注意,后續(xù)的代碼沒有運(yùn)行。這是因?yàn)楫惓J且粋€(gè)會完全停止Go程序執(zhí)行的事件。生成的消息包含多種有助于診斷異常原因的信息。

異常的剖析

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

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

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

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

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

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

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

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

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

Nil接收器

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

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

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

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

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

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

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

運(yùn)行以下代碼,查看從另一個(gè)函數(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

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

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

延遲函數(shù)

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

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

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

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

處理異常

異常只有一個(gè)恢復(fù)機(jī)制——內(nèi)置函數(shù)recover。這個(gè)函數(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!

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

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

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

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

recover檢測異常

recover函數(shù)依賴于錯(cuò)誤的值來確定是否發(fā)生了嚴(yán)重錯(cuò)誤。因?yàn)?code>panic函數(shù)的參數(shù)是一個(gè)空接口,所以它可以是任何類型。任何接口類型的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!

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

相關(guān)文章:

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