Binder Package

The binder package is the core engine of Go Struct Flags. While structflags.Bind() provides an easy way to map standard library flags to structs, the binder package can be used directly for manual control, custom handlers, and lifecycle hooks.

Installation

import "github.com/mirkobrombin/go-struct-flags/v2/pkg/binder"

Basic Usage

The binder reflects on a struct to discover fields tagged with flag and registers default handlers for them.

type Config struct {
    Port int `flag:"port"`
}

cfg := &Config{}
b, _ := binder.NewBinder(cfg)

// Manually run a binding
b.Run("port", []string{"8080"})
fmt.Println(cfg.Port) // 8080

Custom Handlers

You can override or add custom logic for specific keys:

b.AddInt("port", func(val int64) error {
    if val < 1024 {
        return fmt.Errorf("privileged ports not allowed")
    }
    cfg.Port = int(val)
    return nil
})

// Enums
b.AddEnum("mode", []string{"dev", "prod"}, func(val string) error {
    cfg.Mode = val
    return nil
})

// Durations
b.AddDuration("timeout", func(val time.Duration) error {
    cfg.Timeout = val
    return nil
})

Lifecycle Hooks

Hooks allow you to execute logic before or after a value is bound to a field.

b.BeforeHook("port", func(key string, args []string) {
    fmt.Printf("Attempting to bind %s with values %v\n", key, args)
})

b.AfterHook("port", func(key string, args []string) {
    fmt.Printf("Successfully bound %s\n", key)
})

Manual Dispatching

The binder is transport-agnostic. You can use it to bind data from any source (CLI arguments, API requests, configuration files):

// Example: binding from a custom source
data := map[string][]string{
    "port": {"9090"},
}

for k, v := range data {
    if err := b.Run(k, v); err != nil {
        log.Printf("Failed to bind %s: %v", k, err)
    }
}