Wire는 DI(dependency injection)툴로 code generation을 통해 컴포넌트를 연결합니다.
각 컴포넌트의 의존성은 함수의 인자로 표현됩니다.
go install github.com/google/wire/cmd/wire@latest
Event → Greeter → Message 에 각각 의존하는 기본 코드입니다.
package main
import "fmt"
type Message string
type Greeter struct {
Message Message
}
type Event struct {
Greeter Greeter
}
func NewMessage() Message {
return Message("Hi there!")
}
func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
}
func (g Greeter) Greet() Message {
return g.Message
}
func NewEvent(g Greeter) Event {
return Event{Greeter: g}
}
func (e Event) Start() {
msg := e.Greeter.Greet()
fmt.Println(msg)
}
func main() {
message := NewMessage()
greeter := NewGreeter(message)
event := NewEvent(greeter)
event.Start()
}
package main
import "fmt"
/*
...
*/
func main() {
event := InitializeEvent()
event.Start()
}
//+build wireinject
// wire.go 파일
package main
import (
"github.com/google/wire"
)
// wire.go
func InitializeEvent() Event {
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{}
}
Message, Greeter, Event를 각각 만들지 않고 wire.Build
에 initialilzer를 전달합니다.
wire에서는 initializer를 providers
(특정 타입을 반환하는 함수)라고 합니다.
InitializeEvent의 반화 값으로는 컴파일러 오류를 막기 위해 Event 타입을 반환합니다.
wire.go 파일이 새성된 위치로 이동해 wire
명령을 실행하면 wire_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
}
다음 명령으로 빌드 후 실행해보면 처음 파일과 동일한 실행 결과가 나타납니다.
go build -o test .
./test
Hi there!
package main
import (
"os"
"fmt"
"time"
"errors"
)
type Message string
type Greeter struct {
Message Message
Grumpy bool
}
type Event struct {
Greeter Greeter
}
func NewMessage() Message {
return Message("Hi there!")
}
func NewGreeter(m Message) Greeter {
var grumpy bool
if time.Now().Unix()%2 == 0 {
grumpy = true
}
return Greeter{Message: m, Grumpy: grumpy}
}
func (g Greeter) Greet() Message {
if g.Grumpy {
return Message("Go away!")
}
return g.Message
}
func NewEvent(g Greeter) (Event, error) {
if g.Grumpy {
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)
}
func main() {
event, err := InitializeEvent()
if err != nil {
fmt.Printf("failed to create event: %s\n", err)
os.Exit(2)
}
event.Start()
}
NewEvent provider
에서 error를 반환할 수 있도록 수정했습니다.
wire.go 파일에서 InitializeEvent()
함수의 반환 값도 NewEvent()
에 맞춰 변경합니다.
//go:build wireinject
// +build wireinject
package main
import (
"github.com/google/wire"
)
func InitializeEvent() (Event, error){
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{}, nil
}
다시 wire_gen.go 파일을 생성하면 NewEvent()
에서 반환하는 error를 처리하고 있는 것을 볼 수 있습니다.
// 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
}
func InitializeEvent(phrase strting) (Event, error) {
wire.Build(NewEvent, NewGreeter, NewMessage)
return Event{}, nil
}
이제 InitializeEvent()
에 환영 문구를 인자로 전달할 수 있습니다.
func NewMessage(phrase string) Message {
return Message(phrase)
}
// 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(phrase string) (Event, error) {
message := NewMessage(phrase)
greeter := NewGreeter(message)
event, err := NewEvent(greeter)
if err != nil {
return Event{}, err
}
return event, nil
}