go 依赖注入工具( go-wire )使用(二 用户指南)
go 依赖注入工具( go-wire )使用(二 用户指南)
wire 有两个核心概念: 提供者与注入者
提供者providers
providers 是一个能够返回值的方法:
package foobarbaztype Foo struct {X int
}
func ProvideFoo() Foo {return Foo{X: 42}
}type Bar struct {X int
}
func ProvideBar(foo Foo) Bar {return Bar{X: -foo.X}
}type Baz struct {X int
}
func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {if bar.X == 0 {return Baz{}, errors.New("cannot provide baz when bar is zero")}return Baz{X: bar.X}, nil
}
这些都属于提供者。如果经常使用多个提供者,可以将它们放入提供者集合中:
var FooSet = wire.NewSet(ProvideFoo)
var SuperSet = wire.NewSet(FooSet, ProvideBar)
var ProviderSet = wire.NewSet(SuperSet, ProvideBaz)
// or
// var ProviderSet = wire.NewSet(ProvideFoo, ProvideBar, ProvideBaz)
集合可以 自由组合成为新的集合
注射者Injectors
init.go
package foobarbazimport ("context""github.com/google/wire"
)func initializeBaz(ctx context.Context) (Baz, error) {wire.Build(ProviderSet)return Baz{}, nil
}func initializeBar(ctx context.Context) (Bar, error) {wire.Build(ProviderSet)return Bar{}, nil
}func initializeFoo(ctx context.Context) (Foo, error) {wire.Build(ProviderSet)return Foo{}, nil
}
这时运行wire命令就能看到生成的wire_gen.go文件:
// Code generated by Wire. DO NOT EDIT.//go:generate wire
//+build !wireinjectpackage foobarbazimport ("context"
)// Injectors from initBaz.go:func initializeBaz(ctx context.Context) (Baz, error) {foo := ProvideFoo()bar := ProvideBar(foo)baz, err := ProvideBaz(ctx, bar)if err != nil {return Baz{}, err}return baz, nil
}func initializeBar(ctx context.Context) (Bar, error) {foo := ProvideFoo()bar := ProvideBar(foo)return bar, nil
}func initializeFoo(ctx context.Context) (Foo, error) {foo := ProvideFoo()return foo, nil
}
进阶功能
1. 绑定接口
在go 程序中,输出经常是接口的实现,而输入可以是接口。可以通过bind 进行绑定
package bind_interfaceimport "github.com/google/wire"type Fooer interface {Foo() string
}type MyFooer stringfunc (b *MyFooer) Foo() string {return string(*b)
}func provideMyFooer() *MyFooer {b := new(MyFooer)*b = "Hello, World!"return b
}type Bar stringfunc provideBar(f Fooer) string {// f will be a *MyFooer.return f.Foo()
}var Set = wire.NewSet(provideMyFooer,wire.Bind(new(Fooer), new(*MyFooer)), // 使用new(*MyFooer) 的结果代替 Fooer 接口provideBar)
wire.go
// +build wireinjectpackage bind_interfaceimport "github.com/google/wire"func initBar() string {wire.Build(Set)return ""
}
wire_gen.go
// Code generated by Wire. DO NOT EDIT.//go:generate wire
//+build !wireinjectpackage bind_interface// Injectors from wire.go:func initBar() string {myFooer := provideMyFooer()string2 := provideBar(myFooer)return string2
}
2. 构造体提供者
可以指定创建构造体时注入的参数:
package provideStructimport "github.com/google/wire"type Foo int
type Bar intfunc ProvideFoo() Foo {return 0
}func ProvideBar() Bar {return 1
}type FooBar struct {MyFoo FooMyBar Bar
}var Set = wire.NewSet(ProvideFoo,ProvideBar,wire.Struct(new(FooBar), "MyFoo", "MyBar"))
这里指定了填充MyFoo 与 MyBar 两个字段
wire.go
// +build wireinjectpackage provideStructimport "github.com/google/wire"func initFooBar() *FooBar {wire.Build(Set)return nil
}
wire_gen.go
// Code generated by Wire. DO NOT EDIT.//go:generate wire
//+build !wireinjectpackage provideStruct// Injectors from wire.go:func initFooBar() *FooBar {bar := ProvideBar()foo := ProvideFoo()fooBar := &FooBar{MyBar: bar,MyFoo: foo,}return fooBar
}
当然,可以指定只填充一个字段,也可以使用“*” 指定全填充,也可以通过添加tag指定哪个字段不填充(与“-”配合使用)
type FooBar struct {mux sync.Mutex `wire:"-"`MyFoo FooMyBar Bar
}var Set = wire.NewSet(ProvideFoo,ProvideBar,wire.Struct(new(FooBar), "*"))
3. 绑定值
可以提供一个初始化值
package binding_valueimport ("github.com/google/wire"
)type Foo struct {X int
}func injectFoo() Foo {wire.Build(wire.Value(Foo{X:42}))return Foo{}
}
wire结果
func injectFoo() Foo {foo := _wireFooValuereturn foo
}var (_wireFooValue = Foo{X: 42}
)
4. 使用结构体的字段作为提供者
type Foo struct {S stringN intF float64
}func getS(foo Foo) string {return foo.S
}func provideFoo() Foo {return Foo{S: "hello",N: 1, F: 3.14}
}func injectedMessage() string {wire.Build(provideFoo, getS)return ""
}
wire结果
func injectedMessage() string {foo := provideFoo()string2 := getS(foo)return string2
}
可以使用wire.FieldsOf 代替
func injectedFieldMessage() string {wire.Build(provideFoo, wire.FieldsOf(new(Foo),"S"))return ""
}
结果:
func injectedFieldMessage() string {foo := provideFoo()string2 := foo.Sreturn string2
}
5. 清理方法
可以用于数据库,资源关闭等情况
package cleanFuncimport "github.com/google/wire"type Foo struct {}
func (f *Foo) Close() {}
func NewFoo() (*Foo, func(), error) {f := new(Foo)return f, f.Close, nil
}type Bar struct {F *Foo
}
func (b *Bar) Close() {}
func NewBar(f *Foo) (*Bar, func(), error) {b := &Bar{F: f,}return b, b.Close, nil
}type Bzz struct {B *Bar
}
func (b *Bzz) Close() {}
func NewBzz(b *Bar) (*Bzz, func(), error) {bzz := &Bzz{B: b,}return bzz, bzz.Close, nil
}var producer = wire.NewSet(NewFoo, NewBar, NewBzz)
wire.go
func InitApp() (*Bzz, func(), error) {panic(wire.Build(producer))
}
wire_gen.go
func InitApp() (*Bzz, func(), error) {foo, cleanup, err := NewFoo()if err != nil {return nil, nil, err}bar, cleanup2, err := NewBar(foo)if err != nil {cleanup()return nil, nil, err}bzz, cleanup3, err := NewBzz(bar)if err != nil {cleanup2()cleanup()return nil, nil, err}return bzz, func() {cleanup3()cleanup2()cleanup()}, nil
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
