欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言官方依賴注入工具Wire的使用教程

 更新時間:2022年09月23日 14:23:07   作者:高世凱  
依賴注入是一種實(shí)現(xiàn)控制反轉(zhuǎn)且用于解決依賴性問題的設(shè)計(jì)模式。Golang?中常用的依賴注入工具主要有?Inject?、Dig?等。但是今天主要介紹的是?Go?團(tuán)隊(duì)開發(fā)的?Wire,一個編譯期實(shí)現(xiàn)依賴注入的工具,感興趣的可以了解一下

1. 前言

接觸 Golang 有一段時間了,發(fā)現(xiàn) Golang 同樣需要類似 Java 中 Spring 一樣的依賴注入框架。如果項(xiàng)目規(guī)模比較小,是否有依賴注入框架問題不大,但當(dāng)項(xiàng)目變大之后,有一個合適的依賴注入框架是十分必要的。通過調(diào)研,了解到 Golang 中常用的依賴注入工具主要有 Inject 、Dig 等。但是今天主要介紹的是 Go 團(tuán)隊(duì)開發(fā)的 Wire,一個編譯期實(shí)現(xiàn)依賴注入的工具。

2. 依賴注入(DI)是什么

說起依賴注入就要引出另一個名詞控制反轉(zhuǎn)( IoC )。IoC 是一種設(shè)計(jì)思想,其核心作用是降低代碼的耦合度。依賴注入是一種實(shí)現(xiàn)控制反轉(zhuǎn)且用于解決依賴性問題的設(shè)計(jì)模式。

舉個例子,假設(shè)我們代碼分層關(guān)系是 dal 層連接數(shù)據(jù)庫,負(fù)責(zé)數(shù)據(jù)庫的讀寫操作。那么我們的 dal 層的上一層 service 負(fù)責(zé)調(diào)用 dal 層處理數(shù)據(jù),在我們目前的代碼中,它可能是這樣的:

//?dal/user.go

func?(u?*UserDal)?Create(ctx?context.Context,?data?*UserCreateParams)?error?{
????db?:=?mysql.GetDB().Model(&entity.User{})
????user?:=?entity.User{
??????Username:?data.Username,
??????Password:?data.Password,
???}

????return?db.Create(&user).Error
}

//?service/user.go
func?(u?*UserService)?Register(ctx?context.Context,?data?*schema.RegisterReq)?(*schema.RegisterRes,?error)?{
???params?:=?dal.UserCreateParams{
??????Username:?data.Username,
??????Password:?data.Password,
???}

???err?:=?dal.GetUserDal().Create(ctx,?params)
???if?err?!=?nil?{
??????return?nil,?err
???}

???registerRes?:=?schema.RegisterRes{
??????Msg:?"register?success",
???}

???return?&registerRes,?nil
}

在這段代碼里,層級依賴關(guān)系為 service -> dal -> db,上游層級通過 Getxxx實(shí)例化依賴。但在實(shí)際生產(chǎn)中,我們的依賴鏈比較少是垂直依賴關(guān)系,更多的是橫向依賴。即我們一個方法中,可能要多次調(diào)用Getxxx的方法,這樣使得我們代碼極不簡潔。

不僅如此,我們的依賴都是寫死的,即依賴者的代碼中寫死了被依賴者的生成關(guān)系。當(dāng)被依賴者的生成方式改變,我們也需要改變依賴者的函數(shù),這極大的增加了修改代碼量以及出錯風(fēng)險。

接下來我們用依賴注入的方式對代碼進(jìn)行改造:

//?dal/user.go
type?UserDal?struct{
????DB?*gorm.DB
}

func?NewUserDal(db?*gorm.DB)?*UserDal{
????return?&UserDal{
????????DB:?db
????}
}

func?(u?*UserDal)?Create(ctx?context.Context,?data?*UserCreateParams)?error?{
????db?:=?u.DB.Model(&entity.User{})
????user?:=?entity.User{
??????Username:?data.Username,
??????Password:?data.Password,
???}

????return?db.Create(&user).Error
}

//?service/user.go
type?UserService?struct{
????UserDal?*dal.UserDal
}

func?NewUserService(userDal?dal.UserDal)?*UserService{
????return?&UserService{
????????UserDal:?userDal
????}
}

func?(u?*UserService)?Register(ctx?context.Context,?data?*schema.RegisterReq)?(*schema.RegisterRes,?error)?{
???params?:=?dal.UserCreateParams{
??????Username:?data.Username,
??????Password:?data.Password,
???}

???err?:=?u.UserDal.Create(ctx,?params)
???if?err?!=?nil?{
??????return?nil,?err
???}

???registerRes?:=?schema.RegisterRes{
??????Msg:?"register?success",
???}

???return?&registerRes,?nil
}

//?main.go?
db?:=?mysql.GetDB()
userDal?:=?dal.NewUserDal(db)
userService?:=?dal.NewUserService(userDal)

如上編碼情況中,我們通過將 db 實(shí)例對象注入到 dal 中,再將 dal 實(shí)例對象注入到 service 中,實(shí)現(xiàn)了層級間的依賴注入。解耦了部分依賴關(guān)系。

在系統(tǒng)簡單、代碼量少的情況下上面的實(shí)現(xiàn)方式確實(shí)沒什么問題。但是項(xiàng)目龐大到一定程度,結(jié)構(gòu)之間的關(guān)系變得非常復(fù)雜時,手動創(chuàng)建每個依賴,然后層層組裝起來的方式就會變得異常繁瑣,并且容易出錯。這個時候勇士 wire 出現(xiàn)了!

3. Wire Come

3.1 簡介

Wire 是一個輕巧的 Golang 依賴注入工具。它由 Go Cloud 團(tuán)隊(duì)開發(fā),通過自動生成代碼的方式在編譯期完成依賴注入。它不需要反射機(jī)制,后面會看到, Wire 生成的代碼與手寫無異。

3.2 快速使用

wire 的安裝:

go?get?github.com/google/wire/cmd/wire

上面的命令會在 $GOPATH/bin 中生成一個可執(zhí)行程序 wire,這就是代碼生成器??梢园?code>$GOPATH/bin 加入系統(tǒng)環(huán)境變量 $PATH 中,所以可直接在命令行中執(zhí)行 wire 命令。

下面我們在一個例子中看看如何使用 wire。

現(xiàn)在我們有這樣的三個類型:

type?Message?string
type?Channel?struct?{
????Message?Message
}
type?BroadCast?struct?{
????Channel?Channel
}

三者的 init 方法:

func?NewMessage()?Message?{
????return?Message("Hello?Wire!")
}
func?NewChannel(m?Message)?Channel?{
????return?Channel{Message:?m}
}
func?NewBroadCast(c?Channel)?BroadCast?{
????return?BroadCast{Channel:?c}
}

假設(shè) Channel 有一個 GetMsg 方法,BroadCast 有一個 Start 方法:

func?(c?Channel)?GetMsg()?Message?{
????return?c.Message
}

func?(b?BroadCast)?Start()?{
????msg?:=?b.Channel.GetMsg()
????fmt.Println(msg)
}

如果手動寫代碼的話,我們的寫法應(yīng)該是:

func?main()?{
????message?:=?NewMessage()
????channel?:=?NewChannel(message)
????broadCast?:=?NewBroadCast(channel)

????broadCast.Start()
}

如果使用 wire,我們需要做的就變成如下的工作了:

1.提取一個 init 方法 InitializeBroadCast:

func?main()?{
????b?:=?demo.InitializeBroadCast()

????b.Start()
}

2.編寫一個 wire.go 文件,用于 wire 工具來解析依賴,生成代碼:

//+build?wireinject

package?demo

func?InitializeBroadCast()?BroadCast?{
????wire.Build(NewBroadCast,?NewChannel,?NewMessage)
????return?BroadCast{}
}

注意:需要在文件頭部增加構(gòu)建約束://+build wireinject

3.使用 wire 工具,生成代碼,在 wire.go 所在目錄下執(zhí)行命令:wire gen wire.go。會生成如下代碼,即在編譯代碼時真正使用的Init函數(shù):

//?Code?generated?by?Wire.?DO?NOT?EDIT.

//go:generate?wire
//+build?!wireinject
func?InitializeBroadCast()?BroadCast?{
????message?:=?NewMessage()
????channel?:=?NewChannel(message)
????broadCast?:=?NewBroadCast(channel)
????return?broadCast
}

我們告訴 wire,我們所用到的各種組件的 init 方法(NewBroadCastNewChannelNewMessage),那么 wire 工具會根據(jù)這些方法的函數(shù)簽名(參數(shù)類型/返回值類型/函數(shù)名)自動推導(dǎo)依賴關(guān)系。

wire.go 和 wire_gen.go 文件頭部位置都有一個 +build,不過一個后面是 wireinject,另一個是 !wireinject。+build 其實(shí)是 Go 語言的一個特性。類似 C/C++ 的條件編譯,在執(zhí)行 go build 時可傳入一些選項(xiàng),根據(jù)這個選項(xiàng)決定某些文件是否編譯。wire 工具只會處理有wireinject 的文件,所以我們的 wire.go 文件要加上這個。生成的 wire_gen.go 是給我們來使用的,wire 不需要處理,故有 !wireinject

3.3 基礎(chǔ)概念

Wire 有兩個基礎(chǔ)概念,Provider(構(gòu)造器)和 Injector(注入器)

  • Provider 實(shí)際上就是生成組件的普通方法,這些方法接收所需依賴作為參數(shù),創(chuàng)建組件并將其返回。我們上面例子的 NewBroadCast 就是 Provider
  • Injector 可以理解為 Providers 的連接器,它用來按依賴順序調(diào)用 Providers 并最終返回構(gòu)建目標(biāo)。我們上面例子的 InitializeBroadCast 就是 Injector。

4. Wire使用實(shí)踐

下面簡單介紹一下 wire 在飛書問卷表單服務(wù)中的應(yīng)用。

飛書問卷表單服務(wù)的 project 模塊中將 handler 層、service 層和 dal 層的初始化通過參數(shù)注入的方式實(shí)現(xiàn)依賴反轉(zhuǎn)。通過 BuildInjector 注入器來初始化所有的外部依賴。

4.1 基礎(chǔ)使用

dal 偽代碼如下:

func?NewProjectDal(db?*gorm.DB)?*ProjectDal{
????return?&ProjectDal{
????????DB:db
????}
}

type?ProjectDal?struct?{
???DB?*gorm.DB
}

func?(dal?*ProjectDal)?Create(ctx?context.Context,?item?*entity.Project)?error?{
???result?:=?dal.DB.Create(item)
???return?errors.WithStack(result.Error)
}
//?QuestionDal、QuestionModelDal...

service 偽代碼如下:

func?NewProjectService(projectDal?*dal.ProjectDal,?questionDal?*dal.QuestionDal,?questionModelDal?*dal.QuestionModelDal)?*ProjectService?{
???return?&projectService{
??????ProjectDal:???????projectDal,
??????QuestionDal:??????questionDal,
??????QuestionModelDal:?questionModelDal,
???}
}

type?ProjectService?struct?{
???ProjectDal???????*dal.ProjectDal
???QuestionDal??????*dal.QuestionDal
???QuestionModelDal?*dal.QuestionModelDal
}

func?(s?*ProjectService)?Create(ctx?context.Context,?projectBo?*bo.ProjectCreateBo)?(int64,?error)?{}

handler 偽代碼如下:

func?NewProjectHandler(srv?*service.ProjectService)?*ProjectHandler{
????return?&ProjectHandler{
????????ProjectService:?srv
????}
}

type?ProjectHandler?struct?{
???ProjectService?*service.ProjectService
}

func?(s?*ProjectHandler)?CreateProject(ctx?context.Context,?req?*project.CreateProjectRequest)?(resp?*
project.CreateProjectResponse,?err?error)?{}

injector.go 偽代碼如下:

func?NewInjector()(handler?*handler.ProjectHandler)?*Injector{
????return?&Injector{
????????ProjectHandler:?handler
????}
}

type?Injector?struct?{
???ProjectHandler?*handler.ProjectHandler
???//?components,others...
}

在 wire.go 中如下定義:

//?+build?wireinject

package?app

func?BuildInjector()?(*Injector,?error)?{
???wire.Build(
??????NewInjector,

??????//?handler
??????handler.NewProjectHandler,

??????//?services
??????service.NewProjectService,
??????//?更多service...

??????//dal
??????dal.NewProjectDal,
??????dal.NewQuestionDal,
??????dal.NewQuestionModelDal,
??????//?更多dal...

??????//?db
??????common.InitGormDB,
??????//?other?components...
???)

???return?new(Injector),?nil
}

執(zhí)行 wire gen ./internal/app/wire.go 生成 wire_gen.go

//?Code?generated?by?Wire.?DO?NOT?EDIT.

//go:generate?wire
//+build?!wireinject

func?BuildInjector()?(*Injector,?error)?{
???db,?err?:=?common.InitGormDB()
???if?err?!=?nil?{
??????return?nil,?err
???}
???
???projectDal?:=?dal.NewProjectDal(db)
???questionDal?:=?dal.NewQuestionDal(db)
???questionModelDal?:=?dal.NewQuestionModelDal(db)
???projectService?:=?service.NewProjectService(projectDal,?questionDal,?questionModelDal)
???projectHandler?:=?handler.NewProjectHandler(projectService)
???injector?:=?NewInjector(projectHandler)
???return?injector,?nil
}

在 main.go 中加入初始化 injector 的方法 app.BuildInjector

injector,?err?:=?BuildInjector()
if?err?!=?nil?{
???return?nil,?err
}

//project服務(wù)啟動
svr?:=?projectservice.NewServer(injector.ProjectHandler,?logOpt)
svr.Run()

注意,如果你運(yùn)行時,出現(xiàn)了 BuildInjector 重定義,那么檢查一下你的 //+build wireinject 與 package app 這兩行之間是否有空行,這個空行必須要有!見https://github.com/google/wire/issues/117

4.2 高級特性

4.2.1 NewSet

NewSet 一般應(yīng)用在初始化對象比較多的情況下,減少 Injector 里面的信息。當(dāng)我們項(xiàng)目龐大到一定程度時,可以想象會出現(xiàn)非常多的 Providers。NewSet 幫我們把這些 Providers 按照業(yè)務(wù)關(guān)系進(jìn)行分組,組成 ProviderSet(構(gòu)造器集合),后續(xù)只需要使用這個集合即可。

//?project.go
var?ProjectSet?=?wire.NewSet(NewProjectHandler,?NewProjectService,?NewProjectDal)

//?wire.go
func?BuildInjector()?(*Injector,?error)?{
???wire.Build(InitGormDB,?ProjectSet,?NewInjector)

???return?new(Injector),?nil
}

4.2.2 Struct

上述例子的 Provider 都是函數(shù),除函數(shù)外,結(jié)構(gòu)體也可以充當(dāng) Provider 的角色。Wire 給我們提供了結(jié)構(gòu)構(gòu)造器(Struct Provider)。結(jié)構(gòu)構(gòu)造器創(chuàng)建某個類型的結(jié)構(gòu),然后用參數(shù)或調(diào)用其它構(gòu)造器填充它的字段。

//?project_service.go
//?函數(shù)provider
func?NewProjectService(projectDal?*dal.ProjectDal,?questionDal?*dal.QuestionDal,?questionModelDal?*dal.QuestionModelDal)?*ProjectService?{
???return?&projectService{
??????ProjectDal:???????projectDal,
??????QuestionDal:??????questionDal,
??????QuestionModelDal:?questionModelDal,
???}
}

//?等價于
wire.Struct(new(ProjectService),?"*")?//?"*"代表全部字段注入

//?也等價于
wire.Struct(new(ProjectService),?"ProjectDal",?"QuestionDal",?"QuestionModelDal")

//?如果個別屬性不想被注入,那么可以修改?struct?定義:
type?App?struct?{
????Foo?*Foo
????Bar?*Bar
????NoInject?int?`wire:"-"`
}

4.2.3 Bind

Bind 函數(shù)的作用是為了讓接口類型的依賴參與 Wire 的構(gòu)建。Wire 的構(gòu)建依靠參數(shù)類型,接口類型是不支持的。Bind 函數(shù)通過將接口類型和實(shí)現(xiàn)類型綁定,來達(dá)到依賴注入的目的。

//?project_dal.go
type?IProjectDal?interface?{
???Create(ctx?context.Context,?item?*entity.Project)?(err?error)
???//?...
}

type?ProjectDal?struct?{
???DB?*gorm.DB
}

var?bind?=?wire.Bind(new(IProjectDal),?new(*ProjectDal))

4.2.4 CleanUp

構(gòu)造器可以提供一個清理函數(shù)(cleanup),如果后續(xù)的構(gòu)造器返回失敗,前面構(gòu)造器返回的清理函數(shù)都會調(diào)用。初始化 Injector 之后可以獲取到這個清理函數(shù),清理函數(shù)典型的應(yīng)用場景是文件資源和網(wǎng)絡(luò)連接資源。清理函數(shù)通常作為第二返回值,參數(shù)類型為 func()。當(dāng) Provider 中的任何一個擁有清理函數(shù),Injector 的函數(shù)返回值中也必須包含該函數(shù)。并且 Wire 對 Provider 的返回值個數(shù)及順序有以下限制:

  • 第一個返回值是需要生成的對象
  • 如果有 2 個返回值,第二個返回值必須是 func() 或 error
  • 如果有 3 個返回值,第二個返回值必須是 func(),而第三個返回值必須是 error
//?db.go
func?InitGormDB()(*gorm.DB,?func(),?error)?{
????//?初始化db鏈接
????//?...
????cleanFunc?:=?func(){
????????db.Close()
????}

????return?db,?cleanFunc,?nil
}

//?wire.go
func?BuildInjector()?(*Injector,?func(),?error)?{
???wire.Build(
??????common.InitGormDB,
??????//?...
??????NewInjector
???)

???return?new(Injector),?nil,?nil
}

//?生成的wire_gen.go
func?BuildInjector()?(*Injector,?func(),?error)?{
???db,?cleanup,?err?:=?common.InitGormDB()
???//?...
???return?injector,?func(){
???????//?所有provider的清理函數(shù)都會在這里
???????cleanup()
???},?nil
}

//?main.go
injector,?cleanFunc,?err?:=?app.BuildInjector()
defer?cleanFunc()

更多用法具體可以參考 wire官方指南:https://github.com/google/wire/blob/main/docs/guide.md

4.3 高階使用

接著我們就用上述的這些 wire 高級特性對 project 服務(wù)進(jìn)行代碼改造:

project_dal.go

type?IProjectDal?interface?{
???Create(ctx?context.Context,?item?*entity.Project)?(err?error)
???//?...
}

type?ProjectDal?struct?{
???DB?*gorm.DB
}

//?wire.Struct方法是wire提供的構(gòu)造器,"*"代表為所有字段注入值,在這里可以用"DB"代替
//?wire.Bind方法把接口和實(shí)現(xiàn)綁定起來
var?ProjectSet?=?wire.NewSet(
???wire.Struct(new(ProjectDal),?"*"),
???wire.Bind(new(IProjectDal),?new(*ProjectDal)))


func?(dal?*ProjectDal)?Create(ctx?context.Context,?item?*entity.Project)?error?{}
dal.go
//?DalSet?dal注入
var?DalSet?=?wire.NewSet(
???ProjectSet,
???//?QuestionDalSet、QuestionModelDalSet...
)

project_service.go

type?IProjectService?interface?{
???Create(ctx?context.Context,?projectBo?*bo.CreateProjectBo)?(int64,?error)
???//?...
}

type?ProjectService?struct?{
???ProjectDal???????dal.IProjectDal
???QuestionDal??????dal.IQuestionDal
???QuestionModelDal?dal.IQuestionModelDal

}
func?(s?*ProjectService)?Create(ctx?context.Context,?projectBo?*bo.ProjectCreateBo)?(int64,?error)?{}

var?ProjectSet?=?wire.NewSet(
???wire.Struct(new(ProjectService),?"*"),
???wire.Bind(new(IProjectService),?new(*ProjectService)))

service.go

//?ServiceSet?service注入
var?ServiceSet?=?wire.NewSet(
???ProjectSet,
???//?other?service?set...
)

handler 偽代碼如下:

var?ProjectHandlerSet?=?wire.NewSet(wire.Struct(new(ProjectHandler),?"*"))

type?ProjectHandler?struct?{
???ProjectService?service.IProjectService
}

func?(s?*ProjectHandler)?CreateProject(ctx?context.Context,?req?*project.CreateProjectRequest)?(resp?*
project.CreateProjectResponse,?err?error)?{}

injector.go 偽代碼如下:

var?InjectorSet?=?wire.NewSet(wire.Struct(new(Injector),?"*"))

type?Injector?struct?{
???ProjectHandler?*handler.ProjectHandler
???//?others...
}

wire.go

?//?+build?wireinject

package?app


func?BuildInjector()?(*Injector,?func(),?error)?{
???wire.Build(
??????//?db
??????common.InitGormDB,
??????//?dal
??????dal.DalSet,
??????//?services
??????service.ServiceSet,
??????//?handler
??????handler.ProjectHandlerSet,
??????//?injector
??????InjectorSet,
??????//?other?components...
???)

???return?new(Injector),?nil,?nil
}

5. 注意事項(xiàng)

5.1 相同類型問題

wire 不允許不同的注入對象擁有相同的類型。google 官方認(rèn)為這種情況,是設(shè)計(jì)上的缺陷。這種情況下,可以通過類型別名來將對象的類型進(jìn)行區(qū)分。

例如服務(wù)會同時操作兩個 Redis 實(shí)例,RedisA & RedisB

func?NewRedisA()?*goredis.Client?{...}
func?NewRedisB()?*goredis.Client?{...}

對于這種情況,wire 無法推導(dǎo)依賴的關(guān)系??梢赃@樣進(jìn)行實(shí)現(xiàn):

type?RedisCliA?*goredis.Client
type?RedisCliB?*goredis.Client

func?NewRedisA()?RedicCliA?{...}
func?NewRedisB()?RedicCliB?{...}

5.2 單例問題

依賴注入的本質(zhì)是用單例來綁定接口和實(shí)現(xiàn)接口對象間的映射關(guān)系。而通常實(shí)踐中不可避免的有些對象是有狀態(tài)的,同一類型的對象總是要在不同的用例場景發(fā)生變化,單例就會引起數(shù)據(jù)的錯誤,不能保存彼此的狀態(tài)。針對這種場景我們通常設(shè)計(jì)多層的 DI 容器來實(shí)現(xiàn)單例隔離,亦或是脫離 DI 容器自行管理對象的生命周期。

6. 結(jié)語

Wire 是一個強(qiáng)大的依賴注入工具。與 Inject 、Dig 等不同的是,Wire只生成代碼而不是使用反射在運(yùn)行時注入,不用擔(dān)心會有性能損耗。項(xiàng)目工程化過程中,Wire 可以很好協(xié)助我們完成復(fù)雜對象的構(gòu)建組裝。

更多關(guān)于 Wire 的介紹請傳送至:https://github.com/google/wire

到此這篇關(guān)于Go語言官方依賴注入工具Wire的使用教程的文章就介紹到這了,更多相關(guān)Go語言 依賴注入Wire內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang搭建開發(fā)環(huán)境的圖文教程

    Golang搭建開發(fā)環(huán)境的圖文教程

    這篇文章主要介紹了Golang搭建開發(fā)環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Go?container包的介紹

    Go?container包的介紹

    這篇文章主要介紹了Go?container包,go語言container包中有List和Element容器ist和Element都是結(jié)構(gòu)體類型。結(jié)構(gòu)體類型有一個特點(diǎn),那就是它們的零值都會是擁有其特定結(jié)構(gòu),但沒有任何定制化內(nèi)容的值,相當(dāng)于一個空殼,下面一起進(jìn)文章來了解具體內(nèi)容吧
    2021-12-12
  • 解析Golang中的GoPath和GoModule

    解析Golang中的GoPath和GoModule

    在Golang中,有兩個概念非常容易弄錯,第一個就是GoPath,第二個則是GoModule,很多初學(xué)者不清楚這兩者之間的關(guān)系,也就難以清晰地了解項(xiàng)目的整體結(jié)構(gòu),今天通過本文給大家介紹下Golang中的GoPath和GoModule相關(guān)知識,感興趣的朋友一起看看吧
    2022-02-02
  • golang常用庫之配置文件解析庫-viper使用詳解

    golang常用庫之配置文件解析庫-viper使用詳解

    viper 配置管理解析庫,是由大神 Steve Francia 開發(fā),他在google領(lǐng)導(dǎo)著 golang 的產(chǎn)品開發(fā),他也是 gohugo.io 的創(chuàng)始人之一,命令行解析庫 cobra 開發(fā)者,這篇文章主要介紹了golang常用庫之配置文件解析庫-viper使用詳解,需要的朋友可以參考下
    2020-10-10
  • 使用Go?http重試請求的示例

    使用Go?http重試請求的示例

    開發(fā)中對于http請求是經(jīng)常遇到,一般可能網(wǎng)絡(luò)延遲或接口返回超時,這篇文章主要介紹了使用Go?http重試請求的示例,需要的朋友可以參考下
    2022-08-08
  • golang time包做時間轉(zhuǎn)換操作

    golang time包做時間轉(zhuǎn)換操作

    這篇文章主要介紹了golang time包做時間轉(zhuǎn)換操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go語言編程之美自定義二進(jìn)制文件實(shí)用指南

    go語言編程之美自定義二進(jìn)制文件實(shí)用指南

    這篇文章主要介紹了go語言編程之美自定義二進(jìn)制文件實(shí)用指南
    2023-12-12
  • Go語言如何并發(fā)超時處理詳解

    Go語言如何并發(fā)超時處理詳解

    大家都知道golang并沒有在語言層次上提供超時操作,但可以通過一些小技巧實(shí)現(xiàn)超時。下面來一起看看吧,有需要的朋友們可以參考借鑒。
    2016-09-09
  • Go標(biāo)準(zhǔn)庫http?server優(yōu)雅啟動深入理解

    Go標(biāo)準(zhǔn)庫http?server優(yōu)雅啟動深入理解

    這篇文章主要介紹了Go標(biāo)準(zhǔn)庫http?server優(yōu)雅啟動深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Golang::slice和nil的對比分析

    Golang::slice和nil的對比分析

    這篇文章主要介紹了Golang::slice和nil的對比分析,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評論