Go高效率開(kāi)發(fā)Web參數(shù)校驗(yàn)三種方式實(shí)例
web開(kāi)發(fā)中,你肯定見(jiàn)到過(guò)各種各樣的表單或接口數(shù)據(jù)校驗(yàn):
客戶端參數(shù)校驗(yàn):在數(shù)據(jù)提交到服務(wù)器之前,發(fā)生在瀏覽器端或者app應(yīng)用端,相比服務(wù)器端校驗(yàn),用戶體驗(yàn)更好,能實(shí)時(shí)反饋用戶的輸入校驗(yàn)結(jié)果。
服務(wù)器端參數(shù)校驗(yàn):發(fā)生在客戶端提交數(shù)據(jù)并被服務(wù)器端程序接收之后,通常服務(wù)器端校驗(yàn)都是發(fā)生在將數(shù)據(jù)寫(xiě)入數(shù)據(jù)庫(kù)之前,如果數(shù)據(jù)沒(méi)通過(guò)校驗(yàn),則會(huì)直接從服務(wù)器端返回錯(cuò)誤消息,并且告訴客戶端發(fā)生錯(cuò)誤的具體位置和原因,服務(wù)器端校驗(yàn)不像客戶端校驗(yàn)?zāi)菢佑泻玫挠脩趔w驗(yàn),因?yàn)樗钡秸麄€(gè)表單都提交后才能返回錯(cuò)誤信息。但是服務(wù)器端校驗(yàn)是應(yīng)用對(duì)抗錯(cuò)誤,惡意數(shù)據(jù)的最后防線,在這之后,數(shù)據(jù)將被持久化至數(shù)據(jù)庫(kù)。當(dāng)今所有的服務(wù)端框架都提供了數(shù)據(jù)校驗(yàn)與過(guò)濾功能(讓數(shù)據(jù)更安全)。
本文主要討論服務(wù)器端參數(shù)校驗(yàn)
確保用戶以正確格式輸入數(shù)據(jù),提交的數(shù)據(jù)能使后端應(yīng)用程序正常工作,同時(shí)在一切用戶的輸入都是不可信的前提下(比如xss跨域腳本攻擊,sql注入),參數(shù)驗(yàn)證是不可或缺的一環(huán),也是很繁瑣效率不高的一環(huán),在對(duì)接表單提交或者api接口數(shù)據(jù)提交,程序里充斥著大量重復(fù)驗(yàn)證邏輯和if else語(yǔ)句,本文分析參數(shù)校驗(yàn)的三種方式,找出最優(yōu)解,從而提高參數(shù)驗(yàn)證程序代碼的開(kāi)發(fā)效率。
學(xué)習(xí)方式自下而上:提出問(wèn)題 -> 分析問(wèn)題 -> 解決問(wèn)題 -> 總結(jié)
需求場(chǎng)景:
常見(jiàn)的網(wǎng)站登陸場(chǎng)景
業(yè)務(wù)需求
接口一: 場(chǎng)景:輸入手機(jī)號(hào),獲取短信驗(yàn)證碼 校驗(yàn)需求:判斷手機(jī)號(hào)非空,手機(jī)號(hào)格式是否正確 接口二: 場(chǎng)景:手機(jī)收到短信驗(yàn)證碼,輸入驗(yàn)證碼,點(diǎn)擊登陸 校驗(yàn)需求:1、判斷手機(jī)號(hào)非空,手機(jī)號(hào)格式是否正確;2、驗(yàn)證碼非空,驗(yàn)證碼格式是否正確
技術(shù)選型:web框架gin
第一種實(shí)現(xiàn)方式:自定義實(shí)現(xiàn)校驗(yàn)邏輯
package main
func main() {
engine := gin.New()
engine := gin.New()
ctrUser := controller.NewUser()
engine.POST("/user/login", ctrUser.Login)
ctrCaptcha := controller.NewCaptcha()
engine.POST("/captcha/send", ctrCaptcha.Send)
engine.Run()
}
--------------------------------------------------------------------------------
package controller
type Captcha struct {}
func (ctr *Captcha) Send(c *gin.Context) {
mobile := c.PostForm("mobile")
// 校驗(yàn)手機(jī)號(hào)邏輯
if mobile == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "手機(jī)號(hào)不能為空"})
return
}
matched, _ := regexp.MatchString(`^(1[3-9][0-9]\d{8})$`, mobile)
if !matched {
c.JSON(http.StatusBadRequest, gin.H{"error": "手機(jī)號(hào)格式不正確"})
return
}
c.JSON(http.StatusBadRequest, gin.H{"mobile": mobile})
}
type User struct {}
func (ctr *User) Login(c *gin.Context) {
mobile := c.PostForm("mobile")
code := c.PostForm("code")
// 校驗(yàn)手機(jī)號(hào)邏輯
if mobile == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "手機(jī)號(hào)不能為空"})
return
}
matched, _ := regexp.MatchString(`^(1[3-9][0-9]\d{8})$`, mobile)
if !matched {
c.JSON(http.StatusBadRequest, gin.H{"error": "手機(jī)號(hào)格式不正確"})
return
}
// 校驗(yàn)手機(jī)號(hào)邏輯
if code == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "驗(yàn)證碼不能為空"})
return
}
if len(code) != 4 {
c.JSON(http.StatusBadRequest, gin.H{"error": "驗(yàn)證碼為4位"})
return
}
c.JSON(http.StatusBadRequest, gin.H{"mobile": mobile, "code": code})
}
代碼分析:
參數(shù)驗(yàn)證函數(shù)放在Controller層;
這是一種比較初級(jí)也是最樸素的實(shí)現(xiàn)方式,在現(xiàn)實(shí)代碼review中經(jīng)常遇到,這樣實(shí)現(xiàn)會(huì)有什么問(wèn)題?
1、手機(jī)號(hào)碼驗(yàn)證邏輯重復(fù);
2、違背了controller層的職責(zé),controller層充斥著大量的驗(yàn)證函數(shù)(Controller層職責(zé):從HTTP請(qǐng)求中獲得信息,提取參數(shù),并分發(fā)給不同的處理服務(wù));
重復(fù)代碼是軟件質(zhì)量下降的重大來(lái)源?。?!
1、重復(fù)代碼會(huì)造成維護(hù)成本的成倍增加;
2、需求的變動(dòng)導(dǎo)致需要修改重復(fù)代碼,如果遺漏某處重復(fù)的邏輯,就會(huì)產(chǎn)生bug(例如手機(jī)號(hào)碼增加12開(kāi)頭的驗(yàn)證規(guī)則);
3、重復(fù)代碼會(huì)導(dǎo)致項(xiàng)目代碼體積變得臃腫;
聰明的開(kāi)發(fā)者肯定第一時(shí)間想到一個(gè)解決辦法:提取出驗(yàn)證邏輯,工具包util實(shí)現(xiàn)IsMobile函數(shù)
package util
func IsMobile(mobile string) bool {
matched, _ := regexp.MatchString(`^(1[3-9][0-9]\d{8})$`, mobile)
return matched
}
代碼分析:
問(wèn)題:代碼會(huì)大量出現(xiàn)util.IsMobile、util.IsEmail等校驗(yàn)代碼
思考:從面向?qū)ο蟮乃枷氤霭l(fā),IsMobile屬于util的動(dòng)作或行為嗎?
第二種實(shí)現(xiàn)方式:模型綁定校驗(yàn)
技術(shù)選型:web框架gin自帶的模型驗(yàn)證器中文提示不是很好用,這里使用govalidator 模型綁定校驗(yàn)是目前參數(shù)校驗(yàn)最主流的驗(yàn)證方式,每個(gè)編程語(yǔ)言的web框架基本都支持這種模式,模型綁定時(shí)將Http請(qǐng)求中的數(shù)據(jù)映射到模型對(duì)應(yīng)的參數(shù),參數(shù)可以是簡(jiǎn)單類型,如整形,字符串等,也可以是復(fù)雜類型,如Json,Json數(shù)組,對(duì)各種數(shù)據(jù)類型進(jìn)行驗(yàn)證,然后拋出相應(yīng)的錯(cuò)誤信息。
package request
func init() {
validator.TagMap["IsMobile"] = func(value string) bool {
return IsMobile(value)
}
}
func IsMobile(value string) bool {
matched, _ := regexp.MatchString(`^(1[1-9][0-9]\d{8})$`, value)
return matched
}
type Captcha struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
}
type User struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
}
-------------------------------------------------------------------------------
package controller
type Captcha struct {}
func (ctr *Captcha) Send(c *gin.Context) {
request := new(request.Captcha)
if err := c.ShouldBind(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if _, err := validator.ValidateStruct(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusBadRequest, gin.H{"data": request})
}
type User struct {}
func (ctr *User) Login(c *gin.Context) {
request := new(request.User)
if err := c.ShouldBind(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if _, err := validator.ValidateStruct(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusBadRequest, gin.H{"data": request})
}
代碼分析:
1、mobile校驗(yàn)邏輯同樣重復(fù)(注釋實(shí)現(xiàn)校驗(yàn)的邏輯重復(fù),如錯(cuò)誤提示"手機(jī)號(hào)不能為空"修改為"請(qǐng)?zhí)顚?xiě)手機(jī)號(hào)",需要修改兩個(gè)地方)
2、validator.ValidateStruct函數(shù)會(huì)驗(yàn)證結(jié)構(gòu)體所有屬性
對(duì)于2問(wèn)題不太好理解,舉例解釋
業(yè)務(wù)場(chǎng)景:用戶注冊(cè)功能,需要校驗(yàn)手機(jī)號(hào)、短信驗(yàn)證碼、密碼、昵稱、生日
type User struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
Password string `form:"password" valid:"required~密碼不能為空,stringlength(6|18)~密碼6-18個(gè)字符"`
Nickname string `form:"nickname" valid:"required~昵稱不能為空,stringlength(2|10)~昵稱2-10個(gè)字符"`
Birthday time.Time `form:"birthday" valid:"required~生日不能為空" time_format:"2006-01-02"`
}
代碼分析:
登陸功能需要校驗(yàn)Mobile、Code屬性;
注冊(cè)功能需要校驗(yàn)Mobile、Code、Password、Nickname、Birthday屬性;
如果代碼校驗(yàn)共用User結(jié)構(gòu)體,就產(chǎn)生了一個(gè)矛盾點(diǎn),有兩種方法可以解決這一問(wèn)題:
- 修改validator.ValidateStruct函數(shù),增加校驗(yàn)白名單或黑名單,實(shí)現(xiàn)可以設(shè)置部分屬性校驗(yàn)或者忽略校驗(yàn)部分屬性;
// 只做Mobile、Code屬性校驗(yàn)或者忽略Mobile、Code屬性校驗(yàn) validator.ValidateStruct(user, "Mobile", "Code") 這種也是一種不錯(cuò)的解決方式,但是在項(xiàng)目實(shí)踐中會(huì)遇到點(diǎn)小問(wèn)題: 1、一個(gè)校驗(yàn)結(jié)構(gòu)體有20個(gè)屬性,只需要校驗(yàn)其中10個(gè)字段,不管用白名單還是黑名單都需要傳10個(gè)字段; 2、手寫(xiě)字段名容易出錯(cuò);
- 新建不同的結(jié)構(gòu)體,對(duì)應(yīng)相應(yīng)的接口綁定校驗(yàn)
type UserLogin struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
}
type UserRegister struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
Password string `form:"password" valid:"required~密碼不能為空,stringlength(6|18)~密碼6-18個(gè)字符"`
Nickname string `form:"nickname" valid:"required~昵稱不能為空,stringlength(2|10)~昵稱2-10個(gè)字符"`
Birthday time.Time `form:"birthday" valid:"required~生日不能為空" time_format:"2006-01-02"`
}
代碼解析:
用戶登陸接口對(duì)應(yīng):UserLogin結(jié)構(gòu)體
用戶注冊(cè)接口對(duì)應(yīng):UserRegister結(jié)構(gòu)體
同樣問(wèn)題再次出現(xiàn),Mobile、Code屬性校驗(yàn)邏輯重復(fù)。
再介紹第三種參數(shù)校驗(yàn)方式之前,先審視一下剛才的一段代碼:
if err := c.ShouldBind(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if _, err := validator.ValidateStruct(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
參數(shù)綁定校驗(yàn)的地方都需要出現(xiàn)這幾行代碼,我們可以修改gin源碼,把govalidator庫(kù)集成在gin中;
如何修改第三方庫(kù)源代碼參照項(xiàng)目 源碼鏈接
在gin根目錄增加context_validator.go文件,代碼如下:
package gin
import (
"github.com/asaskevich/govalidator"
)
type Validator interface {
Validate() error
}
func (c *Context) ShouldB(data interface{}) error {
if err := c.ShouldBind(data); err != nil {
return err
}
if _, err := govalidator.ValidateStruct(data); err != nil {
return err
}
var v Validator
var ok bool
if v, ok = data.(Validator); !ok {
return nil
}
return v.Validate()
}
controller層的參數(shù)綁定校驗(yàn)代碼如下:
type User struct {}
func (ctr *User) Register(c *gin.Context) {
request := new(request.UserRegister)
if err := c.ShouldB(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusBadRequest, gin.H{"data": request})
}
代碼分析:
增加了Validator接口,校驗(yàn)?zāi)P蛯?shí)現(xiàn)Validator接口,可以完成更為復(fù)雜的多參數(shù)聯(lián)合校驗(yàn)檢查邏輯,如檢查密碼和重復(fù)密碼是否相等
type UserRegister struct {
Mobile string `form:"mobile" valid:"required~手機(jī)號(hào)不能為空,numeric~手機(jī)號(hào)碼應(yīng)該為數(shù)字型,IsMobile~手機(jī)號(hào)碼格式錯(cuò)誤"`
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
Password string `form:"password" valid:"required~密碼不能為空,stringlength(6|18)~密碼6-18個(gè)字符"`
RePassword string `form:"rePassword" valid:"required~重復(fù)密碼不能為空,stringlength(6|18)~重復(fù)密碼6-18個(gè)字符"`
Nickname string `form:"nickname" valid:"required~昵稱不能為空,stringlength(2|10)~昵稱2-10個(gè)字符"`
Birthday time.Time `form:"birthday" valid:"required~生日不能為空" time_format:"2006-01-02"`
}
func (req *UserRegister) Validate() error {
if req.Password != req.RePassword {
return errors.New("兩次密碼不一致")
}
return nil
}
模型校驗(yàn)是通過(guò)反射機(jī)制來(lái)實(shí)現(xiàn),眾所周知反射的效率都不高,現(xiàn)在gin框架集成govalidator,gin原有的校驗(yàn)功能就顯得多余,小伙伴們可以從ShouldBind函數(shù)從下追,把自帶的校驗(yàn)功能屏蔽,提高框架效率。
第三種實(shí)現(xiàn)方式:拆解模型字段,組合結(jié)構(gòu)體
解決字段校驗(yàn)邏輯重復(fù)的最終方法就是拆解字段為獨(dú)立結(jié)構(gòu)體,通過(guò)多個(gè)字段結(jié)構(gòu)體的不同組合為所需的校驗(yàn)結(jié)構(gòu)體,代碼如下:
源碼鏈接
package captcha
type CodeS struct {
Code string `form:"code" valid:"required~驗(yàn)證碼不能為空,numeric~驗(yàn)證碼應(yīng)該為數(shù)字型"`
}
package user
type PasswordS struct {
Password string `form:"password" valid:"required~密碼不能為空,stringlength(6|18)~密碼6-18個(gè)字符"`
}
type RePasswordS struct {
RePassword string `form:"rePassword" valid:"required~重復(fù)密碼不能為空,stringlength(6|18)~重復(fù)密碼6-18個(gè)字符"`
}
type NicknameS struct {
Nickname string `form:"nickname" valid:"required~昵稱不能為空,stringlength(2|10)~昵稱2-10個(gè)字符"`
}
type BirthdayS struct {
Birthday time.Time `form:"birthday" valid:"required~生日不能為空" time_format:"2006-01-02"`
}
type UserLogin struct {
MobileS
captcha.CodeS
}
type UserRegister struct {
MobileS
captcha.CodeS
user.PasswordS
user.RePasswordS
user.NicknameS
user.BirthdayS
}
func (req *UserRegister) Validate() error {
if req.Password() != req.RePassword() {
return errors.New("兩次密碼不一致")
}
return nil
}
代碼解析:
為什么字段結(jié)構(gòu)體都加了S?
1、結(jié)構(gòu)體包含匿名結(jié)構(gòu)體不能調(diào)用匿名結(jié)構(gòu)體同名屬性,匿名結(jié)構(gòu)體加S標(biāo)識(shí)為結(jié)構(gòu)體
示例代碼不能很好的展示項(xiàng)目結(jié)構(gòu),可以查看源代碼
代碼分析:
- 獨(dú)立的字段結(jié)構(gòu)體通常以表名為包名定義范圍,比如商品名稱和分類名稱字段名都為Name,但是所需定義的校驗(yàn)邏輯(字符長(zhǎng)度等)很有可能不同;
- 每一個(gè)接口建立對(duì)應(yīng)的驗(yàn)證結(jié)構(gòu)體:
接口user/login: 對(duì)應(yīng)請(qǐng)求結(jié)構(gòu)體UserLogin 接口user/register: 對(duì)應(yīng)請(qǐng)求結(jié)構(gòu)體UserRegister 接口captcha/send: 對(duì)應(yīng)請(qǐng)求結(jié)構(gòu)體CaptchaSend
- 公用的字段結(jié)構(gòu)體例如ID、Mobile建立單獨(dú)的文件;
總結(jié):
一、驗(yàn)證邏輯封裝在各自的實(shí)體中,由request層實(shí)體負(fù)責(zé)驗(yàn)證邏輯,驗(yàn)證邏輯不會(huì)散落在項(xiàng)目代碼的各個(gè)地方,當(dāng)驗(yàn)證邏輯改變時(shí),找到對(duì)應(yīng)的實(shí)體修改就可以了,這就是代碼的高內(nèi)聚;
二、通過(guò)不同實(shí)體的嵌套組合就可以實(shí)現(xiàn)多樣的驗(yàn)證需求,使得代碼的可重用性大大增強(qiáng),這就是代碼的低耦合
獨(dú)立字段結(jié)構(gòu)體組合成不同的校驗(yàn)結(jié)構(gòu)體,這種方式在實(shí)際項(xiàng)目開(kāi)發(fā)中有很大的靈活性,可以滿足參數(shù)校驗(yàn)比較多變復(fù)雜的需求場(chǎng)景,小伙伴可以在項(xiàng)目開(kāi)發(fā)中慢慢體會(huì)。
參數(shù)綁定校驗(yàn)在項(xiàng)目中遇到的幾個(gè)問(wèn)題
源碼鏈接1、需要提交參數(shù)為json或json數(shù)組如何校驗(yàn)綁定?
type ColumnCreateArticle struct {
IDS
article.TitleS
}
type ColumnCreate struct {
column.TitleS
Article *ColumnCreateArticle `form:"article"`
Articles []ColumnCreateArticle `form:"articles"`
}
2、嚴(yán)格遵循一個(gè)接口對(duì)應(yīng)一個(gè)校驗(yàn)結(jié)構(gòu)體
func (ctr *Column) Detail(c *gin.Context) {
request := new(request.IDS)
if err := c.ShouldB(request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusBadRequest, gin.H{"data": request})
}
示例代碼獲取文章專欄詳情的接口,參數(shù)為專欄id,因?yàn)橹挥幸粋€(gè)id參數(shù),如果剛開(kāi)始圖省事,沒(méi)有建立對(duì)應(yīng)獨(dú)立的ColumnDetail校驗(yàn)結(jié)構(gòu)體,后期接口增加參數(shù)(例如來(lái)源等),還是要改動(dòng)這一塊代碼,增加代碼的不確定性
3、布爾參數(shù)的三種狀態(tài)
type ColumnDetail struct {
IDS
// 為真顯示重點(diǎn)文章,為否顯示非重點(diǎn)文章,為nil都顯示
ArticleIsImportant *bool `form:"articleIsImportant"`
}
column?id=1&articleIsImportant=true ArticleIsImportant為true
column?id=1&articleIsImportant=false ArticleIsImportant為false
column?id=1 ArticleIsIm更多關(guān)于GO語(yǔ)言Web參數(shù)校驗(yàn)方法請(qǐng)查看下面的相關(guān)鏈接
相關(guān)文章
Golang實(shí)現(xiàn)深拷貝reflect原理示例探究
這篇文章主要為大家介紹了Golang實(shí)現(xiàn)reflect深拷貝原理示例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
在Golang中正確的修改HTTPRequest的Host的操作方法
我們工作中經(jīng)常需要通過(guò)HTTP請(qǐng)求Server的服務(wù),比如腳本批量請(qǐng)求接口跑數(shù)據(jù),由于一些網(wǎng)關(guān)策略,部分Server會(huì)要求請(qǐng)求中Header里面附帶Host參數(shù),所以本文給大家介紹了如何在Golang中正確的修改HTTPRequest的Host,需要的朋友可以參考下2023-12-12
詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn)
這篇文章主要介紹了詳解Go語(yǔ)言中關(guān)于包導(dǎo)入必學(xué)的 8 個(gè)知識(shí)點(diǎn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Go語(yǔ)言標(biāo)準(zhǔn)錯(cuò)誤error全面解析
Go語(yǔ)言中的錯(cuò)誤處理是通過(guò)內(nèi)置的error接口來(lái)實(shí)現(xiàn)的,其中errorString和wrapError是兩種常見(jiàn)的錯(cuò)誤類型實(shí)現(xiàn)方式,errorString通過(guò)errors.New()方法實(shí)現(xiàn),而wrapError則通過(guò)fmt.Errorf()方法實(shí)現(xiàn),支持錯(cuò)誤的嵌套和解析2024-10-10
Go Struct結(jié)構(gòu)體的具體實(shí)現(xiàn)
Go語(yǔ)言中通過(guò)結(jié)構(gòu)體的內(nèi)嵌再配合接口比面向?qū)ο缶哂懈叩臄U(kuò)展性和靈活性,本文主要介紹了Go Struct結(jié)構(gòu)體的具體實(shí)現(xiàn),感興趣的可以了解一下2023-03-03
go語(yǔ)言中結(jié)構(gòu)體tag使用小結(jié)
Go語(yǔ)言是一種靜態(tài)類型、編譯型的編程語(yǔ)言,其中結(jié)構(gòu)體是一種非常重要的數(shù)據(jù)類型,本文就來(lái)介紹一下go語(yǔ)言中結(jié)構(gòu)體tag使用,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
一文掌握Go語(yǔ)言并發(fā)編程必備的Mutex互斥鎖
Go 語(yǔ)言提供了 sync 包,其中包括 Mutex 互斥鎖、RWMutex 讀寫(xiě)鎖等同步機(jī)制,本篇博客將著重介紹 Mutex 互斥鎖的基本原理,需要的可以參考一下2023-04-04

