作者:andruzhang,騰訊 IEG 后臺開發工程師
創新互聯建站,是成都地區的互聯網解決方案提供商,用心服務為企業提供網站建設、重慶APP開發、微信小程序開發、系統定制網站建設和微信代運營服務。經過數10多年的沉淀與積累,沉淀的是技術和服務,讓客戶少走彎路,踏實做事,誠實做人,用情服務,致力做一個負責任、受尊敬的企業。對客戶負責,就是對自己負責,對企業負責。
在后臺開發中,針對錯誤處理,有三個維度的問題需要解決:
一個面向過程的函數,在不同的處理過程中需要 handle 不同的錯誤信息;一個面向對象的函數,針對一個操作所返回的不同類型的錯誤,有可能需要進行不同的處理。此外,在遇到錯誤時,也可以使用斷言的方式,快速中止函數流程,大大提高代碼的可讀性。
在許多高級語言中都提供了 try ... catch 的語法,函數內部可以通過這種方案,實現一個統一的錯誤處理邏輯。而即便是 C 這種 “中級語言” 雖然沒有,但是程序員也可以使用宏定義的方式,來實現某種程度上的錯誤斷言。
但是,對于 Go 的情況就比較尷尬了。
我們先來看斷言,我們的目的是,僅使用一行代碼就能夠檢查錯誤并終止當前函數。由于沒有 throw,沒有宏,如果要實現一行斷言,有兩種方法。
第一種是把 if 的錯誤判斷寫在一行內,比如:
第二種方法是借用 panic 函數,結合 recover 來實現:
這兩種方法都值得商榷。
首先,將 if 寫在同一行內的問題有:
至于第二種方法,我們要分情況看;
不過使用 panic 來斷言的方案,雖然在業務邏輯中基本上不用,但在測試場景下則是非常常見的。測試嘛,用牛刀有何不可?稍微大一點的系統開銷也沒啥問題。對于 Go 來說,非常熱門的單元測試框架 goconvey 就是使用 panic 機制來實現單元測試中的斷言,用的人都說好。
綜上,在 Go 中,對于業務代碼,筆者不建議采用斷言,遇到錯誤的時候建議還是老老實實采用這種格式:
而在單測代碼中,則完全可以大大方方地采用類似于 goconvey 之類基于 panic 機制的斷言。
眾所周知 Go 是沒有 try ... catch 的,而且從官方的態度來看,短時間內也沒有考慮的計劃。但程序員有這個需求呀。筆者采用的方法,是將需要返回的 err 變量在函數內部全局化,然后結合 defer 統一處理:
這種方案要特別注意變量作用域問題.比如前面的 if err = DoSomething(); err != nil { 行,如果我們將 err = ... 改為 err := ...,那么這一行中的 err 變量和函數最前面定義的 (err error) 不是同一個變量,因此即便在此處發生了錯誤,但是在 defer 函數中無法捕獲到 err 變量了。
在 try ... catch 方面,筆者其實沒有特別好的方法來模擬,即便是上面的方法也有一個很讓人頭疼的問題:defer 寫法導致錯誤處理前置,而正常邏輯后置了,從可讀性的角度來說非常不友好。因此也希望讀者能夠指教。同時還是希望 Go 官方能夠繼續迭代,支持這種語法。
這一點在 Go 里面,一開始看起來還是比較統一的,這就是 Go 最開始就定義的 error 類型,以系統標準的方式,統一了進程內函數級的錯誤返回模式。調用方使用 if err != nil 的統一模式,來判斷一個調用是不是成功了。
但是隨著 Go 的逐步推廣,由于 error 接口的高自由度,程序員們對于 “如何判斷該錯誤是什么錯誤” 的時候,出現了分歧。
在 Go 1.13 之前,對于 error 類型的傳遞,有三種常見的模式:
這個流派很簡單,就是將各種錯誤信息直接定義為一個類枚舉值的模式,比如:
當遇到相應的錯誤信息時,直接返回對應的 error 類枚舉值就行了。對于調用方也非常方便,可以采用 switch - case 來判斷錯誤類型:
個人覺得這種設計模式本質上還是 C error code 模式。
這種流派則是充分使用了 “error 是一個 interface” 的特性,重新自定義一個 error 類型。一方面是用不同的類型來表示不同的錯誤分類,另一方面則能夠實現對于同一錯誤類型,能夠給調用方提供更佳詳盡的信息。舉個例子,我們可以定義多個不同的錯誤類型如下:
對于調用方,則通過以下代碼來判斷不同的錯誤:
這種模式,一方面可以透傳底層錯誤,另一方面又可以添加自定義的信息。但對于調用方而言,災難在于如果要判斷某一個錯誤的具體類型,只能用 strings.Contains() 來實現,而錯誤的具體描述文字是不可靠的,同一類型的信息可能會有不同的表達;而在 fmt.Errorf 的過程中,各個業務添加的額外信息也可能會有不同的文字,這帶來了極大的不可靠性,提高了模塊之間的耦合度。
在 go 1.13 版本發布之后,針對 fmt.Errorf 增加了 wraping 功能,并在 errors 包中添加了 Is() 和 As() 函數。關于這個模式的原理和使用已經有很多文章了,本文就不再贅述。
這個功能,合并并改造了前文的所謂 “== 流派” 和 “fmt.Errorf” 流派,統一使用 errors.Is() 函數;此外,也算是官方對類型斷言流派的認可(專門用 As() 函數來支持)。
在實際應用中,函數/模塊透傳錯誤時,應該采用 Go 的 error wrapping 模式,也就是 fmt.Errorf() 配合 %w 使用,業務方可以放心地添加自己的錯誤信息,只要調用方統一采用 errors.Is() 和 errors.As() 即可。
服務/系統層面的錯誤信息返回,大部分協議都可以看成是 code - message 模式或者是其變體:
這種模式的特點是:code 是給程序代碼使用的,代碼判斷這是一個什么類型的錯誤,進入相應的分支處理;而 message 是給人看的,程序可以以某種形式拋出或者記錄這個錯誤信息,供用戶查看。
在這一層面有什么問題呢?code for computer,message for user,好像挺好的。
但有時候,我們可能會收到用戶/客戶反饋一個問題:“XXX 報錯了,幫忙看看什么問題?”。用戶看不懂我們的錯誤提示嗎?
在筆者的經驗中,我們在使用 code - message 機制的時候,特別是業務初期,難以避免的是前后端的設計文案沒能完整地覆蓋所有的錯誤用例,或者是錯誤極其罕見。因此當出現錯誤時,提示曖昧不清(甚至是直接提示錯誤信息),導致用戶從錯誤信息中找到解決方案
在這種情況下,盡量覆蓋所有錯誤路徑肯定是最完美的方法。不過在做到這一點之前,碼農們往往有下面的解決方案:
既要隱藏信息,又要暴露信息,我可以摔盤子嗎……
這里,筆者從日益普及的短信驗證碼有了個靈感——人的短期記憶對 4 個字符還是比較強的,因此我們可以考慮把錯誤代碼縮短到 4 個字符——不區分大小寫,因為如果人在記憶時還要記錄大小寫的話,難度會增加不少。
怎么用 4 個字符表示盡量多的數據呢?數字+字母總共有 36 個字符,理論上使用 4 位 36 進制可以表示 36x36x36x36 = 1679616 個值。因此我們只要找到一個針對錯誤信息字符串的哈希算法,把輸出值限制在 1679616 范圍內就行了。
這里我采用的是 MD5 作為例子。MD5 的輸出是 128 位,理論上我可以取 MD5 的輸出,模 1679616 就可以得到一個簡易的結果。實際上為了減少除法運算,我采用的是取高 20 位(0xFFFFF)的簡易方式(20 位二進制的最大值為 1048575),然后將這個數字轉成 36 進制的字符串輸出。
當出現異常錯誤時,我們可以將 message 的提示信息如下展示:“未知錯誤,錯誤代碼 30EV,如需協助,請聯系 XXX”。順帶一提,30EV 是 "Access denied for user 'db_user'@'127.0.0.1'" 的計算結果,這樣一來,我就對調用方隱藏了敏感信息。
至于后臺側,還是需要實實在在地將這個哈希值和具體的錯誤信息記錄在日志或者其他支持搜索的渠道里。當用戶提供該代碼時,可以快速定位。
這種方案的優點很明顯:
簡易的錯誤碼生成代碼如下:
當然這種方案也有局限性,筆者能想到的是需要注意以下兩點:
此外,筆者需要再強調的是:在開發中,針對各種不同的、正式的錯誤用例依然需要完整覆蓋,盡可能通過已有的 code - message 機制將足夠清晰的信息告知主調方。這種 hashcode 的錯誤代碼生成方法,僅適用于錯誤用例遺漏、或者是快速迭代過程中,用于發現和調試遺漏的錯誤用例的臨時方案。
1、簡單易學。
Go語言的作者本身就很懂C語言,所以同樣Go語言也會有C語言的基因,所以對于程序員來說,Go語言天生就會讓人很熟悉,容易上手。
2、并發性好。
Go語言天生支持并發,可以充分利用多核,輕松地使用并發。 這是Go語言最大的特點。
描述
Go的語法接近C語言,但對于變量的聲明有所不同。Go支持垃圾回收功能。Go的并行模型是以東尼·霍爾的通信順序進程(CSP)為基礎,采取類似模型的其他語言包括Occam和Limbo,但它也具有Pi運算的特征,比如通道傳輸。
在1.8版本中開放插件(Plugin)的支持,這意味著現在能從Go中動態加載部分函數。
與C++相比,Go并不包括如枚舉、異常處理、繼承、泛型、斷言、虛函數等功能,但增加了 切片(Slice) 型、并發、管道、垃圾回收、接口(Interface)等特性的語言級支持。
可以。
1.首先,打開鼠標驅動(鼠標宏設置都是大同小異),選擇“宏”設置,然后進入宏設置頁面。
2.點擊鼠標界面上的“側面圖”進入子鍵“宏”設置
3. ?進入側鍵“宏”設置后,編輯界面上的"+"號進入錄制界面
4. ?點擊界面上的“錄制”按鈕即可錄制編輯,?所有鼠標帶“宏”設置功能的操作方法都是一樣的,就像編寫程序一樣設置響應事件即可完成你想要的操作。
5. ?根據你在游戲里需要的操作,進行所需要的游戲編輯
《反恐精英:全球攻勢》(英文:Counter-Strike: Global Offensive),通常簡稱為CSGO。是由Valve Software開發的射擊游戲作品,由Steam發行。
它由最新一代起源引擎(起源引擎2012)開發,并繼承了絕大部分的經典反恐精英設計,是繼《反恐精英:起源》后第五部《反恐精英》作品。它主要針對《CS1.6》和《CS:起源》對新手玩家不太友好這點做出改進,《CS:GO》還會通過綜合勝負百分比、作戰場次和擊殺比率等一系列因素,將實力更接近的玩家組合成對抗雙方,開發者希望這樣可以讓比賽更加平衡。
2016年7月27日,完美世界宣布獲得該游戲在中國大陸運營代理權,CS:GO正式登陸國服。
golang定義可變參數的函數方法是:
—- 采用ANSI標準形式時,參數個數可變的函數的原型聲明是:
type funcname(type para1, type para2, …)
—- 這種形式至少需要一個普通的形式參數,后面的省略號不表示省略,而是函數原型的一部分。type是函數返回值和形式參數的類型。
—- 采用與UNIX System V兼容的聲明方式時,參數個數可變的函數原型是:
type funcname(va_alist)
va_dcl
—- 這種形式不需要提供任何普通的形式參數。
type是函數返回值的類型。va_dcl是對函數原型聲明中參數va_alist的詳細聲明,實際是一個宏定義,對不同的硬件平臺采用不同的類型來定義,但在最后都包括了一個分號。因此va_dcl后不再需要加上分號了。va_dcl在代碼中必須原樣給出。va_alist在VC中可以原樣給出,也可以略去。
此外,采用頭文件stdarg.h編寫的程序是符合ANSI標準的,可以在各種操作系統和硬件上運行;而采用頭文件varargs.h的方式僅僅是為了與以前的程序兼容。所以建議使用前者。
很遺憾,Go中沒有這樣的設計,當然,目前大多數相對高級的語言都取消了宏定義的方法,雖然這樣降低了程序員對程序的掌控能力,但是這樣更容易保證程序運行的一致性。俗話說,有舍也有得吧。
對于想要實現Release版本與Develop版本體現不一樣的運行效果,可以通過定義特殊的標記常量或者變量來實現,這一點在Java等很多語言上都是一樣的。
1、學習曲線
它包含了類C語法、GC內置和工程工具。這一點非常重要,因為Go語言容易學習,所以一個普通的大學生花一個星期就能寫出來可以上手的、高性能的應用。在國內大家都追求快,這也是為什么國內Go流行的原因之一。
2、效率
Go擁有接近C的運行效率和接近PHP的開發效率,這就很有利的支撐了上面大家追求快速的需求。
3、出身名門、血統純正
之所以說Go語言出身名門,是因為我們知道Go語言出自Google公司,這個公司在業界的知名度和實力自然不用多說。Google公司聚集了一批牛人,在各種編程語言稱雄爭霸的局面下推出新的編程語言,自然有它的戰略考慮。而且從Go語言的發展態勢來看,Google對它這個新的寵兒還是很看重的,Go自然有一個良好的發展前途。我們看看Go語言的主要創造者,血統純正這點就可見端倪了。
4、組合的思想、無侵入式的接口
Go語言可以說是開發效率和運行效率二者的完美融合,天生的并發編程支持。Go語言支持當前所有的編程范式,包括過程式編程、面向對象編程以及函數式編程。
5、強大的標準庫
這包括互聯網應用、系統編程和網絡編程。Go里面的標準庫基本上已經是非常穩定,特別是我這里提到的三個,網絡層、系統層的庫非常實用。
6、部署方便
我相信這一點是很多人選擇Go的最大理由,因為部署太方便,所以現在也有很多人用Go開發運維程序。
7、簡單的并發
它包含降低心智的并發和簡易的數據同步,我覺得這是Go最大的特色。之所以寫正確的并發、容錯和可擴展的程序如此之難,是因為我們用了錯誤的工具和錯誤的抽象,Go可以說這一塊做的相當簡單。
8、穩定性
Go擁有強大的編譯檢查、嚴格的編碼規范和完整的軟件生命周期工具,具有很強的穩定性,穩定壓倒一切。那么為什么Go相比于其他程序會更穩定呢?這是因為Go提供了軟件生命周期的各個環節的工具,如go
tool、gofmt、go test。
文章題目:go語言支持宏定義嗎,golang 宏定義
文章轉載:http://vcdvsql.cn/article16/heoggg.html
成都網站建設公司_創新互聯,為您提供定制開發、關鍵詞優化、虛擬主機、網站導航、網站改版、手機網站建設
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯