最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang中的依賴注入之wire的使用

 更新時(shí)間:2026年02月26日 09:36:02   作者:涼涼的知識(shí)庫  
wire是Google開源的一個(gè)依賴注入工具,它是一個(gè)代碼生成器,本文就來介紹一下golang中的依賴注入之wire的使用,具有一定的參考價(jià)值,感興趣的可以了解一下

Wire

wire是 Google 開源的一個(gè)依賴注入工具。它是一個(gè)代碼生成器,并不是一個(gè)框架。我們只需要在一個(gè)特殊的go文件中告訴wire類型之間的依賴關(guān)系,它會(huì)自動(dòng)幫我們生成代碼,幫助我們創(chuàng)建指定類型的對(duì)象,并組裝它的依賴。

安裝

$ go install github.com/google/wire/cmd/wire@latest

兩個(gè)概念

正式開始前需要先了解一下 wire 當(dāng)中的兩個(gè)概念:providerinjector

Provider

Provider 是一個(gè)普通的函數(shù),這個(gè)函數(shù)會(huì)返回構(gòu)建依賴關(guān)系所需的組件。如下所示,就是一個(gè) provider 函數(shù),在實(shí)際使用的時(shí)候,往往是一些簡單的工廠函數(shù),這個(gè)函數(shù)不會(huì)太復(fù)雜。

// NewPostRepo 創(chuàng)建文章 Repo
func NewPostRepo() IPostRepo {}

不過需要注意的是在 wire 中不能存在兩個(gè) provider 返回相同的組件類型

Injector

injector 也是一個(gè)普通函數(shù),我們常常在 wire.go 文件中定義 injector 函數(shù)簽名,然后通過 wire 命令自動(dòng)生成一個(gè)完整的函數(shù)

//+build wireinject

func GetBlogService() *Blog {
    panic(wire.Build(NewBlogService, NewPostUsecase, NewPostRepo))
}

第一行的 //+build wireinject 注釋確保了這個(gè)文件在我們正常編譯的時(shí)候不會(huì)被引用,而 wire . 生成的文件 wire_gen.go 會(huì)包含 //+build !wireinject 注釋,正常編譯的時(shí)候,不指定 tag 的情況下會(huì)引用這個(gè)文件

wire.Buildinjector 函數(shù)中使用,用于表名這個(gè) injector 由哪些 provider 提供依賴, injector 函數(shù)本身只是一個(gè)函數(shù)簽名,所以我們直接在函數(shù)中 panic 實(shí)際生成代碼的時(shí)候并不會(huì)直接調(diào)用 panic

示例

type Message string

func NewMessage() Message {
	return Message("Hi there!")
}

type Greeter struct {
	Message Message
}

func NewGreeter(m Message) Greeter {
	return Greeter{Message: m}
}

func (g Greeter) Greet() Message {
	return g.Message
}

type Event struct {
	Greeter Greeter // <- adding a Greeter field
}

func NewEvent(g Greeter) Event {
	return Event{Greeter: g}
}

func (e Event) Start() {
	msg := e.Greeter.Greet()
	fmt.Println(msg)
}

設(shè)計(jì)一個(gè)程序,其中 Event依賴Greeter,Greeter依賴Message

如果我們手動(dòng)構(gòu)建Event則需要

func main() {
    message := NewMessage()
    greeter := NewGreeter(message)
    event := NewEvent(greeter)

    event.Start()
}

使用wire生成代碼

對(duì)于上面的NewEvent、NewGreeter、NewMessage都是provider

我們只要再創(chuàng)建一個(gè)獨(dú)立的文件 wrie.go,并在里面創(chuàng)建一個(gè)Injector即可

//go:build wireinject
// +build wireinject

package main

import "github.com/google/wire"

func InitializeEvent() Event {
	panic(wire.Build(NewEvent, NewGreeter, NewMessage))
}

在執(zhí)行完wire命令之后就會(huì)生成wire_gen.go,它的內(nèi)容就是構(gòu)建 Event。我們需要連同wire_gen.go一起提交到版本控制系統(tǒng)里

// Code generated by Wire. DO NOT EDIT.

//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject

package main

// Injectors from wire.go:

func InitializeEvent() Event {
	message := NewMessage()
	greeter := NewGreeter(message)
	event := NewEvent(greeter)
	return event
}

此時(shí)我們就可以直接在main里這樣用

func main() {
	event := InitializeEvent()
	event.Start()
}

返回錯(cuò)誤

在 go 中如果遇到錯(cuò)誤,我們會(huì)在最后一個(gè)返回值返回 error,wire 同樣也支持返回錯(cuò)誤的情況,只需要在 injector 的函數(shù)簽名中加上 error 返回值即可

調(diào)整Provider的簽名

type Event struct {
	Greeter Greeter
}

//func NewEvent(g Greeter) Event {
//	return Event{Greeter: g}
//}
func NewEvent(g Greeter) (Event, error) {
	if time.Now().Unix()%2 == 0 {
		return Event{}, errors.New("could not create event: event greeter is grumpy")
	}

	return Event{Greeter: g}, nil
}

func (e Event) Start() {
	msg := e.Greeter.Greet()
	fmt.Println(msg)
}

調(diào)整Injector的簽名

func InitializeEvent() (Event, error) {
	panic(wire.Build(NewEvent, NewGreeter, NewMessage))
}

生成的代碼如下所示,可以發(fā)現(xiàn)會(huì)像我們自己寫代碼一樣判斷一下 if err 然后返回

// Code generated by Wire. DO NOT EDIT.

//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject

package main

// Injectors from wire.go:

func InitializeEvent() (Event, error) {
	message := NewMessage()
	greeter := NewGreeter(message)
	event, err := NewEvent(greeter)
	if err != nil {
		return Event{}, err
	}
	return event, nil
}

main中的調(diào)用

func main() {
    e, err := InitializeEvent()
    if err != nil {
        fmt.Printf("failed to create event: %s\n", err)
        os.Exit(2)
    }
    e.Start()
}

傳入?yún)?shù)

調(diào)整Provider的簽名

type Message string

//func NewMessage() Message {
//	return Message("Hi there!")
//}
func NewMessage(phrase string) Message {
	return Message(phrase)
}

調(diào)整Injector的簽名

func InitializeEvent(phrase string) (Event, error) {
	panic(wire.Build(NewEvent, NewGreeter, NewMessage))
}

不展示生成的代碼了,main中的調(diào)用

func main() {
	event, err := InitializeEvent("Hi there!")
	if err != nil {
		fmt.Printf("failed to create event: %s\n", err)
		os.Exit(2)
	}

	event.Start()
}

ProviderSet

有時(shí)候可能多個(gè)類型有相同的依賴,我們每次都將相同的構(gòu)造器傳給wire.Build()不僅繁瑣,而且不易維護(hù),一個(gè)依賴修改了,所有傳入wire.Build()的地方都要修改。為此,wire提供了一個(gè)ProviderSet(構(gòu)造器集合),可以將多個(gè)構(gòu)造器打包成一個(gè)集合,后續(xù)只需要使用這個(gè)集合即可。

如下,后續(xù)再調(diào)整NewGreeterNewMessage,就可以統(tǒng)一改了

package main

import "github.com/google/wire"

var wireSet = wire.NewSet(NewGreeter, NewMessage)

func InitializeEvent(phrase string) (Event, error) {
	panic(wire.Build(wireSet, NewEvent))
}

func InitializeEvent2(phrase string) (Event, error) {
	panic(wire.Build(wireSet, NewEvent))
}

結(jié)構(gòu)構(gòu)造器

對(duì)于Greeter前面使用NewGreeter作為Provider

type Greeter struct {
	Message Message
}

func NewGreeter(m Message, phrase string) Greeter {
	return Greeter{Message: m}
}

如果不顯式實(shí)現(xiàn)NewGreeter,可以直接使用wire提供的結(jié)構(gòu)構(gòu)造器(Struct Provider)。結(jié)構(gòu)構(gòu)造器創(chuàng)建某個(gè)類型的結(jié)構(gòu),然后用參數(shù)或調(diào)用其它構(gòu)造器填充它的字段

結(jié)構(gòu)構(gòu)造器使用wire.Struct注入,第一個(gè)參數(shù)固定為new(結(jié)構(gòu)名),后面可接任意多個(gè)參數(shù),表示需要為該結(jié)構(gòu)的哪些字段注入值

我們也可以使用通配符*表示注入所有字段

var wireSet = wire.NewSet(NewMessage, wire.Struct(new(Greeter), "Message"))

func InitializeEvent(phrase string) (Event, error) {
	panic(wire.Build(wireSet, NewEvent))
}

結(jié)構(gòu)字段作為構(gòu)造器

有時(shí)候我們編寫一個(gè)構(gòu)造器,只是簡單的返回某個(gè)結(jié)構(gòu)的一個(gè)字段,這時(shí)可以使用wire.FieldsOf簡化操作。

type Foo struct {
    S string
    N int
    F float64
}

func getS(foo Foo) string {
    // Bad! Use wire.FieldsOf instead.
    return foo.S
}

func provideFoo() Foo {
    return Foo{ S: "Hello, World!", N: 1, F: 3.14 }
}

func injectedMessage() string {
    wire.Build(
        provideFoo,
        getS)
    return ""
}
func injectedMessage() string {
    wire.Build(
        provideFoo,
        wire.FieldsOf(new(Foo), "S"))
    return ""
}

同樣的,第一個(gè)參數(shù)為new(結(jié)構(gòu)名),后面跟多個(gè)參數(shù)表示將哪些字段作為構(gòu)造器,*表示全部。

綁定值

有時(shí)候,我們需要為某個(gè)類型綁定一個(gè)值,而不想依賴構(gòu)造器每次都創(chuàng)建一個(gè)新的值。有些類型天生就是單例,例如配置,數(shù)據(jù)庫對(duì)象(sql.DB)。這時(shí)我們可以使用wire.Value綁定值,使用wire.InterfaceValue綁定接口

修改一下 Greeter 使他依賴一個(gè) int 和 io.Reader 然后為它直接綁定 a=10 io.Reader = os.Stdin

// main.go
var singletonMessage = NewMessage("Hello, world!")

type Message string

func NewMessage(phrase string) Message {
	return Message(phrase)
}

type Greeter struct {
	a int
	r io.Reader

	Message Message
}

func NewGreeter(m Message, phrase string) Greeter {
	return Greeter{Message: m}
}

func (g Greeter) Greet() Message {
	return g.Message
}
var wireSet = wire.NewSet(
	wire.Struct(new(Greeter), "*"),
	wire.Value(10),
	wire.InterfaceValue(new(io.Reader), os.Stdin),
	wire.Value(singletonMessage),
)

func InitializeEvent(phrase string) (Event, error) {
	panic(wire.Build(wireSet, NewEvent))
}

綁定接口

使用 wire.BindStruct 和接口進(jìn)行綁定,表示這個(gè)結(jié)構(gòu)體實(shí)現(xiàn)了這個(gè)接口,wire.Bind 的使用方法就是 wire.Bind(new(接口), new(實(shí)現(xiàn)))

func NewGreeter(m Message, phrase string) Greeter {
	return Greeter{Message: m}
}

func (g Greeter) Greet() Message {
	return g.Message
}

type IGreeter interface{
	Greet() Message
}

type Event struct {
	Greeter IGreeter
}
var wireSet = wire.NewSet(
	wire.Struct(new(Greeter), "*"),
	wire.Value(10),
	wire.InterfaceValue(new(io.Reader), os.Stdin),
	wire.Value(singletonMessage),
)

func InitializeEvent(phrase string) (Event, error) {
	panic(wire.Build(wireSet, NewEvent, wire.Bind(new(IGreeter), new(*Greeter))))
}

到此這篇關(guān)于golang中的依賴注入之wire的文章就介紹到這了,更多相關(guān)golang 依賴注入wire內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go中regexp包常見的正則表達(dá)式操作

    Go中regexp包常見的正則表達(dá)式操作

    本文主要介紹了Go中regexp包常見的正則表達(dá)式操作,包括匹配、查找、替換和分割字符串等,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • golang基礎(chǔ)之Gocurrency并發(fā)

    golang基礎(chǔ)之Gocurrency并發(fā)

    這篇文章主要介紹了golang基礎(chǔ)之Gocurrency并發(fā),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • GO語言實(shí)現(xiàn)簡單TCP服務(wù)的方法

    GO語言實(shí)現(xiàn)簡單TCP服務(wù)的方法

    這篇文章主要介紹了GO語言實(shí)現(xiàn)簡單TCP服務(wù)的方法,實(shí)例分析了Go語言實(shí)現(xiàn)TCP服務(wù)的技巧,需要的朋友可以參考下
    2015-03-03
  • 一文了解Go語言io.Copy函數(shù)

    一文了解Go語言io.Copy函數(shù)

    這篇文章主要為大家介紹了Go語言io.Copy函數(shù)使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Golang?RPC的原理與簡單調(diào)用詳解

    Golang?RPC的原理與簡單調(diào)用詳解

    RPC(Remote?Procedure?Call),主要是幫助我們屏蔽網(wǎng)絡(luò)編程細(xì)節(jié)?,使我們更專注于業(yè)務(wù)邏輯,所以本文主要來和大家聊聊RPC的原理與簡單調(diào)用,希望對(duì)大家有所幫助
    2023-05-05
  • Go語言中的函數(shù)、閉包、defer、錯(cuò)誤處理的學(xué)習(xí)教程

    Go語言中的函數(shù)、閉包、defer、錯(cuò)誤處理的學(xué)習(xí)教程

    Go語言中函數(shù)包含func關(guān)鍵字、函數(shù)名、參數(shù)列表和返回值列表,Go支持普通函數(shù)、匿名函數(shù)和閉包,值傳遞是Go語言中所有函數(shù)參數(shù)的傳遞方式,defer語句用于延遲函數(shù)的執(zhí)行,適合用于資源清理,Go的錯(cuò)誤處理主要通過error接口、panic函數(shù)和recover函數(shù)來實(shí)現(xiàn),鼓勵(lì)顯式錯(cuò)誤處理
    2026-01-01
  • 一文詳解Golang如何解決內(nèi)存溢出

    一文詳解Golang如何解決內(nèi)存溢出

    內(nèi)存溢出是指程序在運(yùn)行時(shí)超出了分配給它的內(nèi)存限制,從而導(dǎo)致程序異常或崩潰的現(xiàn)象,本文主要為大家介紹了Golang解決內(nèi)存溢出的方法,感興趣的小伙伴可以了解下
    2025-01-01
  • 詳解golang中模板的常用語法

    詳解golang中模板的常用語法

    這篇文章主要介紹了golang模板中的常用語法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • Go?實(shí)現(xiàn)?WebSockets之創(chuàng)建?WebSockets

    Go?實(shí)現(xiàn)?WebSockets之創(chuàng)建?WebSockets

    這篇文章主要介紹了Go?實(shí)現(xiàn)?WebSockets之創(chuàng)建?WebSockets,文章主要探索?WebSockets,并簡要介紹了它們的工作原理,并仔細(xì)研究了全雙工通信,想了解更多相關(guān)內(nèi)容的小伙伴可以參考一下
    2022-04-04
  • Go語言中利用http發(fā)起Get和Post請(qǐng)求的方法示例

    Go語言中利用http發(fā)起Get和Post請(qǐng)求的方法示例

    這篇文章主要給大家介紹了關(guān)于Go語言中利用http發(fā)起Get和Post請(qǐng)求的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11

最新評(píng)論

元朗区| 株洲县| 祁阳县| 广昌县| 虹口区| 宕昌县| 平舆县| 阿勒泰市| 呼玛县| 肥乡县| 昌乐县| 广元市| 金门县| 嘉定区| 华安县| 庐江县| 门源| 韶关市| 芒康县| 左权县| 清徐县| 崇礼县| 陇南市| 弥渡县| 南充市| 芜湖市| 贵南县| 信阳市| 双鸭山市| 民乐县| 海阳市| 安平县| 桑日县| 老河口市| 庆云县| 峨边| 余江县| 镇宁| 西城区| 新宁县| 江孜县|