Wire

gowire

安装

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

两个概念

providerinjector

Provider

Providerprovider
// NewPostRepo 创建文章 Repo
func NewPostRepo() IPostRepo {}

不过需要注意的是在 wire 中不能存在两个 provider 返回相同的组件类型

Injector

wire.goinjectorwire
//+build wireinject

func GetBlogService() *Blog {
    panic(wire.Build(NewBlogService, NewPostUsecase, NewPostRepo))
}
//+build wireinjectwire .wire_gen.go//+build !wireinject
wire.Buildinjectorinjectorproviderinjectorpanic

示例

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)
}
EventGreeterGreeterMessage
Event
func main() {
    message := NewMessage()
    greeter := NewGreeter(message)
    event := NewEvent(greeter)

    event.Start()
}

使用wire生成代码

NewEventNewGreeterNewMessageprovider
wrie.goInjector
//go:build wireinject
// +build wireinject

package main

import "github.com/google/wire"

func InitializeEvent() Event {
    panic(wire.Build(NewEvent, NewGreeter, NewMessage))
}
wirewire_gen.goEventwire_gen.go
// 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
}

此时我们就可以直接在main里这样用

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

返回错误

在 go 中如果遇到错误,我们会在最后一个返回值返回 error,wire 同样也支持返回错误的情况,只需要在 injector 的函数签名中加上 error 返回值即可

调整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)
}

调整Injector的签名

func InitializeEvent() (Event, error) {
    panic(wire.Build(NewEvent, NewGreeter, NewMessage))
}
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中的调用

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

传入参数

调整Provider的签名

type Message string

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

调整Injector的签名

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

不展示生成的代码了,main中的调用

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

wire.Build()wire.Build()wireProviderSet
NewGreeterNewMessage
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))
}

结构构造器

GreeterNewGreeterProvider
type Greeter struct {
    Message Message
}

func NewGreeter(m Message, phrase string) Greeter {
    return Greeter{Message: m}
}
NewGreeterwire
wire.Structnew(结构名)
*
var wireSet = wire.NewSet(NewMessage, wire.Struct(new(Greeter), "Message"))

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

结构字段作为构造器

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 ""
}
new(结构名)*

绑定值

sql.DBwire.Valuewire.InterfaceValue
Greetera=10io.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.BindStructwire.Bindwire.Bind(new(接口), new(实现))
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))))
}

参考