go語言error變量,go語言 全局變量

golang err是字符串類型的嗎

不是,是error類型。

成都創(chuàng)新互聯(lián)專注于做網(wǎng)站、網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、網(wǎng)站制作、網(wǎng)站開發(fā)。公司秉持“客戶至上,用心服務(wù)”的宗旨,從客戶的利益和觀點(diǎn)出發(fā),讓客戶在網(wǎng)絡(luò)營銷中找到自己的駐足之地。尊重和關(guān)懷每一位客戶,用嚴(yán)謹(jǐn)?shù)膽B(tài)度對待客戶,用專業(yè)的服務(wù)創(chuàng)造價值,成為客戶值得信賴的朋友,為客戶解除后顧之憂。

Golang中的error類型

error類型本身就是一個預(yù)定義好的接口,里面定義了一個method

type error interface {

Error() string

}

深入剖析:一套在 Go 中傳遞、返回、暴露錯誤,便于回查的解決方案

作者:andruzhang,騰訊 IEG 后臺開發(fā)工程師

在后臺開發(fā)中,針對錯誤處理,有三個維度的問題需要解決:

一個面向過程的函數(shù),在不同的處理過程中需要 handle 不同的錯誤信息;一個面向?qū)ο蟮暮瘮?shù),針對一個操作所返回的不同類型的錯誤,有可能需要進(jìn)行不同的處理。此外,在遇到錯誤時,也可以使用斷言的方式,快速中止函數(shù)流程,大大提高代碼的可讀性。

在許多高級語言中都提供了 try ... catch 的語法,函數(shù)內(nèi)部可以通過這種方案,實(shí)現(xiàn)一個統(tǒng)一的錯誤處理邏輯。而即便是 C 這種 “中級語言” 雖然沒有,但是程序員也可以使用宏定義的方式,來實(shí)現(xiàn)某種程度上的錯誤斷言。

但是,對于 Go 的情況就比較尷尬了。

我們先來看斷言,我們的目的是,僅使用一行代碼就能夠檢查錯誤并終止當(dāng)前函數(shù)。由于沒有 throw,沒有宏,如果要實(shí)現(xiàn)一行斷言,有兩種方法。

第一種是把 if 的錯誤判斷寫在一行內(nèi),比如:

第二種方法是借用 panic 函數(shù),結(jié)合 recover 來實(shí)現(xiàn):

這兩種方法都值得商榷。

首先,將 if 寫在同一行內(nèi)的問題有:

至于第二種方法,我們要分情況看;

不過使用 panic 來斷言的方案,雖然在業(yè)務(wù)邏輯中基本上不用,但在測試場景下則是非常常見的。測試嘛,用牛刀有何不可?稍微大一點(diǎn)的系統(tǒng)開銷也沒啥問題。對于 Go 來說,非常熱門的單元測試框架 goconvey 就是使用 panic 機(jī)制來實(shí)現(xiàn)單元測試中的斷言,用的人都說好。

綜上,在 Go 中,對于業(yè)務(wù)代碼,筆者不建議采用斷言,遇到錯誤的時候建議還是老老實(shí)實(shí)采用這種格式:

而在單測代碼中,則完全可以大大方方地采用類似于 goconvey 之類基于 panic 機(jī)制的斷言。

眾所周知 Go 是沒有 try ... catch 的,而且從官方的態(tài)度來看,短時間內(nèi)也沒有考慮的計劃。但程序員有這個需求呀。筆者采用的方法,是將需要返回的 err 變量在函數(shù)內(nèi)部全局化,然后結(jié)合 defer 統(tǒng)一處理:

這種方案要特別注意變量作用域問題.比如前面的 if err = DoSomething(); err != nil { 行,如果我們將 err = ... 改為 err := ...,那么這一行中的 err 變量和函數(shù)最前面定義的 (err error) 不是同一個變量,因此即便在此處發(fā)生了錯誤,但是在 defer 函數(shù)中無法捕獲到 err 變量了。

在 try ... catch 方面,筆者其實(shí)沒有特別好的方法來模擬,即便是上面的方法也有一個很讓人頭疼的問題:defer 寫法導(dǎo)致錯誤處理前置,而正常邏輯后置了,從可讀性的角度來說非常不友好。因此也希望讀者能夠指教。同時還是希望 Go 官方能夠繼續(xù)迭代,支持這種語法。

這一點(diǎn)在 Go 里面,一開始看起來還是比較統(tǒng)一的,這就是 Go 最開始就定義的 error 類型,以系統(tǒng)標(biāo)準(zhǔn)的方式,統(tǒng)一了進(jìn)程內(nèi)函數(shù)級的錯誤返回模式。調(diào)用方使用 if err != nil 的統(tǒng)一模式,來判斷一個調(diào)用是不是成功了。

但是隨著 Go 的逐步推廣,由于 error 接口的高自由度,程序員們對于 “如何判斷該錯誤是什么錯誤” 的時候,出現(xiàn)了分歧。

在 Go 1.13 之前,對于 error 類型的傳遞,有三種常見的模式:

這個流派很簡單,就是將各種錯誤信息直接定義為一個類枚舉值的模式,比如:

當(dāng)遇到相應(yīng)的錯誤信息時,直接返回對應(yīng)的 error 類枚舉值就行了。對于調(diào)用方也非常方便,可以采用 switch - case 來判斷錯誤類型:

個人覺得這種設(shè)計模式本質(zhì)上還是 C error code 模式。

這種流派則是充分使用了 “error 是一個 interface” 的特性,重新自定義一個 error 類型。一方面是用不同的類型來表示不同的錯誤分類,另一方面則能夠?qū)崿F(xiàn)對于同一錯誤類型,能夠給調(diào)用方提供更佳詳盡的信息。舉個例子,我們可以定義多個不同的錯誤類型如下:

對于調(diào)用方,則通過以下代碼來判斷不同的錯誤:

這種模式,一方面可以透傳底層錯誤,另一方面又可以添加自定義的信息。但對于調(diào)用方而言,災(zāi)難在于如果要判斷某一個錯誤的具體類型,只能用 strings.Contains() 來實(shí)現(xiàn),而錯誤的具體描述文字是不可靠的,同一類型的信息可能會有不同的表達(dá);而在 fmt.Errorf 的過程中,各個業(yè)務(wù)添加的額外信息也可能會有不同的文字,這帶來了極大的不可靠性,提高了模塊之間的耦合度。

在 go 1.13 版本發(fā)布之后,針對 fmt.Errorf 增加了 wraping 功能,并在 errors 包中添加了 Is() 和 As() 函數(shù)。關(guān)于這個模式的原理和使用已經(jīng)有很多文章了,本文就不再贅述。

這個功能,合并并改造了前文的所謂 “== 流派” 和 “fmt.Errorf” 流派,統(tǒng)一使用 errors.Is() 函數(shù);此外,也算是官方對類型斷言流派的認(rèn)可(專門用 As() 函數(shù)來支持)。

在實(shí)際應(yīng)用中,函數(shù)/模塊透傳錯誤時,應(yīng)該采用 Go 的 error wrapping 模式,也就是 fmt.Errorf() 配合 %w 使用,業(yè)務(wù)方可以放心地添加自己的錯誤信息,只要調(diào)用方統(tǒng)一采用 errors.Is() 和 errors.As() 即可。

服務(wù)/系統(tǒng)層面的錯誤信息返回,大部分協(xié)議都可以看成是 code - message 模式或者是其變體:

這種模式的特點(diǎn)是:code 是給程序代碼使用的,代碼判斷這是一個什么類型的錯誤,進(jìn)入相應(yīng)的分支處理;而 message 是給人看的,程序可以以某種形式拋出或者記錄這個錯誤信息,供用戶查看。

在這一層面有什么問題呢?code for computer,message for user,好像挺好的。

但有時候,我們可能會收到用戶/客戶反饋一個問題:“XXX 報錯了,幫忙看看什么問題?”。用戶看不懂我們的錯誤提示嗎?

在筆者的經(jīng)驗(yàn)中,我們在使用 code - message 機(jī)制的時候,特別是業(yè)務(wù)初期,難以避免的是前后端的設(shè)計文案沒能完整地覆蓋所有的錯誤用例,或者是錯誤極其罕見。因此當(dāng)出現(xiàn)錯誤時,提示曖昧不清(甚至是直接提示錯誤信息),導(dǎo)致用戶從錯誤信息中找到解決方案

在這種情況下,盡量覆蓋所有錯誤路徑肯定是最完美的方法。不過在做到這一點(diǎn)之前,碼農(nóng)們往往有下面的解決方案:

既要隱藏信息,又要暴露信息,我可以摔盤子嗎……

這里,筆者從日益普及的短信驗(yàn)證碼有了個靈感——人的短期記憶對 4 個字符還是比較強(qiáng)的,因此我們可以考慮把錯誤代碼縮短到 4 個字符——不區(qū)分大小寫,因?yàn)槿绻嗽谟洃洉r還要記錄大小寫的話,難度會增加不少。

怎么用 4 個字符表示盡量多的數(shù)據(jù)呢?數(shù)字+字母總共有 36 個字符,理論上使用 4 位 36 進(jìn)制可以表示 36x36x36x36 = 1679616 個值。因此我們只要找到一個針對錯誤信息字符串的哈希算法,把輸出值限制在 1679616 范圍內(nèi)就行了。

這里我采用的是 MD5 作為例子。MD5 的輸出是 128 位,理論上我可以取 MD5 的輸出,模 1679616 就可以得到一個簡易的結(jié)果。實(shí)際上為了減少除法運(yùn)算,我采用的是取高 20 位(0xFFFFF)的簡易方式(20 位二進(jìn)制的最大值為 1048575),然后將這個數(shù)字轉(zhuǎn)成 36 進(jìn)制的字符串輸出。

當(dāng)出現(xiàn)異常錯誤時,我們可以將 message 的提示信息如下展示:“未知錯誤,錯誤代碼 30EV,如需協(xié)助,請聯(lián)系 XXX”。順帶一提,30EV 是 "Access denied for user 'db_user'@'127.0.0.1'" 的計算結(jié)果,這樣一來,我就對調(diào)用方隱藏了敏感信息。

至于后臺側(cè),還是需要實(shí)實(shí)在在地將這個哈希值和具體的錯誤信息記錄在日志或者其他支持搜索的渠道里。當(dāng)用戶提供該代碼時,可以快速定位。

這種方案的優(yōu)點(diǎn)很明顯:

簡易的錯誤碼生成代碼如下:

當(dāng)然這種方案也有局限性,筆者能想到的是需要注意以下兩點(diǎn):

此外,筆者需要再強(qiáng)調(diào)的是:在開發(fā)中,針對各種不同的、正式的錯誤用例依然需要完整覆蓋,盡可能通過已有的 code - message 機(jī)制將足夠清晰的信息告知主調(diào)方。這種 hashcode 的錯誤代碼生成方法,僅適用于錯誤用例遺漏、或者是快速迭代過程中,用于發(fā)現(xiàn)和調(diào)試遺漏的錯誤用例的臨時方案。

golang 結(jié)構(gòu)體與error 的問題?

要進(jìn)行強(qiáng)制類型轉(zhuǎn)換才行,像這樣:

fmt.Printf("%+v\n",((WriteException)c).b)

Go語言os標(biāo)準(zhǔn)庫常用方法Getwd/Getenv/Chdir

1. os.Getwd()函數(shù)

原型:func Getwd()(pwd string, err error)

作用:獲取當(dāng)前文件路徑

返回:當(dāng)前文件路徑的字符串和一個err信息

示例:

輸出:

當(dāng)前路徑: D:ProjectsGomGoLab01

2. os.Getenv()函數(shù)

原型:func Getenv(key string) string

作用:獲取系統(tǒng)環(huán)境變量的值

參數(shù):key - 系統(tǒng)環(huán)境變量名

返回:系統(tǒng)環(huán)境變量的值

示例:

輸出:

環(huán)境變量GOPATH的值是: D:/Projects/Go

3. os.Chdir()函數(shù)

原型:func Chdir(dir string) error

作用:將當(dāng)前文件路徑改變?yōu)槟繕?biāo)路徑(非真實(shí)改變)

參數(shù):dir - 目標(biāo)路徑(即改變之后的路徑)

返回:修改成功,返回 nil;修改失?。ㄈ纾耗繕?biāo)路徑不存在的情況),返回錯誤信息。

示例一:

輸出:

起始路徑: D:ProjectsGomGoLab01

修改后的路徑: D:ProjectsGoDemo02

示例二:

輸出:

起始路徑: D:ProjectsGomGoLab01

error: chdir D:ProjectsGoDemo03: The system cannot find the file specified.

注:文件路徑,Window 系統(tǒng)下默認(rèn)是“”,寫在代碼中時要用“”或“/”代替。

Go語言變量的作用域

2021-10-22

每一個變量(常量、類型或函數(shù))在程序中都有一定的作用范圍。稱之為作用域。

Go語言在編譯時會檢查每一個變量是否使用過,未使用過的變量就會編譯錯誤。

根據(jù)變量定義位置的不同,可以分為以下三個類型:

在函數(shù)體內(nèi)被聲明的變量稱之為局部變量,作用在函數(shù)體內(nèi),函數(shù)的參數(shù)和返回值變量都屬于局部變量。局部變量不會一直存在,在函數(shù)被調(diào)用時存在,函數(shù)調(diào)用結(jié)束后變量就會被銷毀,即生命周期。

例子:其中a、b均為局部變量,只會在main函數(shù)內(nèi)有效

在函數(shù)體外被聲明的變量稱之為全局變量,作用于所有源文件。不包含這個全局變量的源文件需要使用"import"關(guān)鍵字引入全局變量所在的源文件之后才能使用這個全局變量。

全局變量聲明必須以 var 關(guān)鍵字開頭,如果想要在外部包中使用全局變量的首字母必須大寫。

例如:global為全局在main2和main函數(shù)中都能使用

函數(shù)名后面的小括號里定義的變量, 用于接受來自調(diào)用函數(shù)的參數(shù)。用于接收調(diào)用該函數(shù)時傳入的參數(shù)。

例如:下面的例子中,第十七行a、b為sum函數(shù)定義的形參,用于傳入main函數(shù)中的AF、BF

go語言返回的error為什么可以不接收

error 類型介紹

error 類型實(shí)際上是抽象了 Error() 方法的 error 接口,Golang 使用該接口進(jìn)行標(biāo)準(zhǔn)的錯誤處理。

復(fù)制代碼代碼如下:

type error interface {

Error() string

}

一般情況下,如果函數(shù)需要返回錯誤,就將 error 作為多個返回值中的最后一個(但這并非是強(qiáng)制要求)。參考模型:

復(fù)制代碼代碼如下:

func Foo(param int) (n int, err error) {

// ...

}

if n, err := Foo(0); err != nil {

// 錯誤處理

}

文章名稱:go語言error變量,go語言 全局變量
本文鏈接:http://muchs.cn/article28/phiscp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站設(shè)計靜態(tài)網(wǎng)站、App設(shè)計、做網(wǎng)站、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司