### Install mapstructure Source: https://github.com/go-viper/mapstructure/blob/main/README.md Use this command to install the mapstructure library using Go modules. ```shell go get github.com/go-viper/mapstructure/v2 ``` -------------------------------- ### Example JSON for dynamic decoding Source: https://github.com/go-viper/mapstructure/blob/main/README.md This JSON structure demonstrates a scenario where the 'type' field determines the subsequent data structure, making dynamic decoding with mapstructure beneficial. ```json { "type": "person", "name": "Mitchell" } ``` -------------------------------- ### Transform Field Names with MapFieldName in Go Source: https://context7.com/go-viper/mapstructure/llms.txt Use the `MapFieldName` option in `DecoderConfig` to provide a custom function that transforms input map keys to match struct field names. This example converts snake_case keys to PascalCase for struct fields. ```go package main import ( "fmt" "strings" "unicode" "github.com/go-viper/mapstructure/v2" ) type UserProfile struct { FirstName string LastName string EmailAddr string } // toSnakeCase converts PascalCase to snake_case func toSnakeCase(s string) string { var result strings.Builder for i, r := range s { if unicode.IsUpper(r) { if i > 0 { result.WriteRune('_') } result.WriteRune(unicode.ToLower(r)) } else { result.WriteRune(r) } } return result.String() } func main() { input := map[string]any{ "first_name": "John", "last_name": "Doe", "email_addr": "john@example.com", } var result UserProfile config := &mapstructure.DecoderConfig{ MapFieldName: toSnakeCase, Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("%s %s <%s>", result.FirstName, result.LastName, result.EmailAddr) // Output: John Doe } ``` -------------------------------- ### Convert Strings to net.IP and net.IPNet with Hooks Source: https://context7.com/go-viper/mapstructure/llms.txt Utilize StringToIPHookFunc and StringToIPNetHookFunc to parse string representations of IP addresses and IP networks into their respective Go types. ```go package main import ( "fmt" "net" "github.com/go-viper/mapstructure/v2" ) type NetworkConfig struct { ServerIP net.IP AllowedNet net.IPNet } func main() { input := map[string]any{ "server_ip": "192.168.1.100", "allowed_net": "10.0.0.0/8", } var result NetworkConfig config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToIPHookFunc(), mapstructure.StringToIPNetHookFunc(), ), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("Server: %v, Network: %v", result.ServerIP, result.AllowedNet.String()) // Output: Server: 192.168.1.100, Network: 10.0.0.0/8 } ``` -------------------------------- ### Create Customizable Decoder with DecoderConfig Source: https://context7.com/go-viper/mapstructure/llms.txt Use NewDecoder with DecoderConfig to set advanced options like WeaklyTypedInput, ErrorUnused, and Result. This provides fine-grained control over the decoding process. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int Emails []string } func main() { input := map[string]any{ "name": 123, "age": "42", "emails": map[string]any{}, } var result Person config := &mapstructure.DecoderConfig{ WeaklyTypedInput: true, ErrorUnused: false, // Set to true to error on unused keys Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("%#v", result) // Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}} } ``` -------------------------------- ### Use Go modules replace for temporary migration Source: https://github.com/go-viper/mapstructure/blob/main/README.md If immediate code migration is not feasible, you can use the Go modules 'replace' directive in your go.mod file to temporarily use this fork while maintaining compatibility with older versions. ```go replace github.com/mitchellh/mapstructure => github.com/go-viper/mapstructure v1.6.0 ``` -------------------------------- ### Compose Multiple Decode Hooks Source: https://context7.com/go-viper/mapstructure/llms.txt Combine several decode hooks into a single, sequential hook using `ComposeDecodeHookFunc`. Each hook processes the data passed from the previous one, enabling complex data transformations. ```go package main import ( "fmt" "reflect" "strings" "time" "github.com/go-viper/mapstructure/v2" ) type Config struct { Name string Timeout time.Duration Tags []string } func main() { input := map[string]any{ "name": " MyService ", "timeout": "5s", "tags": "web,api,public", } // Custom hook to trim strings trimHook := func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() == reflect.String && t.Kind() == reflect.String { return strings.TrimSpace(data.(string)), nil } return data, nil } var result Config config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( trimHook, mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), ), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("Name: %q, Timeout: %v, Tags: %v", result.Name, result.Timeout, result.Tags) // Output: Name: "MyService", Timeout: 5s, Tags: [web api public] } ``` -------------------------------- ### Convert Strings to time.Time with StringToTimeHookFunc Source: https://context7.com/go-viper/mapstructure/llms.txt Use StringToTimeHookFunc to convert string values to time.Time objects. Specify the expected time layout format for accurate parsing. ```go package main import ( "fmt" time "time" "github.com/go-viper/mapstructure/v2" ) type Event struct { Name string StartTime time.Time } func main() { input := map[string]any{ "name": "Conference", "start_time": "2024-01-15T09:00:00Z", } var result Event config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("Event: %s at %v", result.Name, result.StartTime.Format("Jan 2, 2006")) // Output: Event: Conference at Jan 15, 2024 } ``` -------------------------------- ### Migrate mapstructure import path Source: https://github.com/go-viper/mapstructure/blob/main/README.md This shell command can be used to automatically update import paths in your Go project when migrating from the original mapstructure library to this fork. ```shell sed -i 's|github.com/mitchellh/mapstructure|github.com/go-viper/mapstructure/v2|g' $(find . -type f -name '*.go') ``` -------------------------------- ### Convert Strings to Slices with StringToSliceHookFunc Source: https://context7.com/go-viper/mapstructure/llms.txt Employ StringToSliceHookFunc to split string values into string slices using a specified separator. This is useful for comma-separated or delimited values. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Config struct { AllowedHosts []string EnabledFlags []string } func main() { input := map[string]any{ "allowed_hosts": "localhost,example.com,api.example.com", "enabled_flags": "debug;verbose;trace", } var result Config config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToSliceHookFunc(","), ), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } // Decode allowed_hosts with comma separator err = decoder.Decode(map[string]any{"allowed_hosts": input["allowed_hosts"]}) if err != nil { panic(err) } fmt.Printf("Hosts: %v", result.AllowedHosts) // Output: Hosts: [localhost example.com api.example.com] } ``` -------------------------------- ### Convert Strings to time.Duration Source: https://context7.com/go-viper/mapstructure/llms.txt Use the built-in `StringToTimeDurationHookFunc` to automatically convert string representations of durations (e.g., "30s", "500ms") into `time.Duration` values. ```go package main import ( "fmt" "time" "github.com/go-viper/mapstructure/v2" ) type Config struct { Timeout time.Duration RetryDelay time.Duration } func main() { input := map[string]any{ "timeout": "30s", "retry_delay": "500ms", } var result Config config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeDurationHookFunc(), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("Timeout: %v, RetryDelay: %v", result.Timeout, result.RetryDelay) // Output: Timeout: 30s, RetryDelay: 500ms } ``` -------------------------------- ### Omit Zero Values with Omitempty and Omitzero Tags Source: https://context7.com/go-viper/mapstructure/llms.txt Employ `omitempty` to exclude fields with zero-length values (e.g., empty strings, nil slices) and `omitzero` to exclude fields with zero values (e.g., 0 for integers, false for booleans) during encoding to maps. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string `mapstructure:",omitempty"` Age int `mapstructure:",omitzero"` Emails []string `mapstructure:",omitempty"` } func main() { input := Person{ Name: "Mitchell", Age: 0, // Will be omitted due to omitzero Emails: nil, // Will be omitted due to omitempty } result := make(map[string]any) err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("%v", result) // Output: map[Name:Mitchell] } ``` -------------------------------- ### ErrorUnused and ErrorUnset Configuration for Strict Decoding Source: https://context7.com/go-viper/mapstructure/llms.txt Configure the decoder to enforce strictness by enabling ErrorUnused to catch extra keys in the input map and ErrorUnset to ensure all required struct fields are populated. This is useful for validating input data against a defined structure. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type StrictConfig struct { Host string Port int Database string } func main() { input := map[string]any{ "host": "localhost", "port": 5432, "unknown": "value", // This will cause an error with ErrorUnused } var result StrictConfig config := &mapstructure.DecoderConfig{ ErrorUnused: true, // Error if input has keys not in struct ErrorUnset: true, // Error if struct fields are not set Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { fmt.Printf("Error: %v", err) // Output: Error: decoding failed due to the following error(s): // // 'StrictConfig' has invalid keys: unknown // '' has unset fields: Database } } ``` -------------------------------- ### Custom DecodeHookFunc for Complex Type Transformations Source: https://context7.com/go-viper/mapstructure/llms.txt Implement custom decode hooks to handle complex type conversions, such as parsing a custom string format into a struct. Ensure the hook correctly identifies target types and input kinds before performing the transformation. ```go package main import ( "fmt" "reflect" "strconv" "strings" "github.com/go-viper/mapstructure/v2" ) type Coordinates struct { Latitude float64 Longitude float64 } type Location struct { Name string Coords Coordinates } func main() { input := map[string]any{ "name": "Sydney", "coords": "-33.8688#151.2093", // Custom format: lat#lon } coordsHook := func(f reflect.Type, t reflect.Type, data any) (any, error) { if t != reflect.TypeOf(Coordinates{}) || f.Kind() != reflect.String { return data, nil } parts := strings.Split(data.(string), "#") if len(parts) != 2 { return data, nil } lat, err := strconv.ParseFloat(parts[0], 64) if err != nil { return nil, err } lon, err := strconv.ParseFloat(parts[1], 64) if err != nil { return nil, err } return Coordinates{Latitude: lat, Longitude: lon}, nil } var result Location config := &mapstructure.DecoderConfig{ DecodeHook: coordsHook, Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("%s: %.4f, %.4f", result.Name, result.Coords.Latitude, result.Coords.Longitude) // Output: Sydney: -33.8688, 151.2093 } ``` -------------------------------- ### Decode Map to Struct with Metadata Tracking Source: https://context7.com/go-viper/mapstructure/llms.txt DecodeMetadata tracks which keys were decoded, which were unused, and which struct fields were left unset. This is helpful for data validation and debugging. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int } func main() { input := map[string]any{ "name": "Mitchell", "age": 91, "email": "foo@bar.com", // This key is not in the struct } var md mapstructure.Metadata var result Person err := mapstructure.DecodeMetadata(input, &result, &md) if err != nil { panic(err) } fmt.Printf("Keys: %v\n", md.Keys) fmt.Printf("Unused keys: %v\n", md.Unused) // Output: // Keys: [Name Age] // Unused keys: [email] } ``` -------------------------------- ### Implement Unmarshaler Interface for Custom Decoding Source: https://context7.com/go-viper/mapstructure/llms.txt Define an UnmarshalMapstructure method on your type to gain full control over how mapstructure decodes data into it, allowing for custom logic, defaults, and validation. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type ServerConfig struct { Host string Port int } func (s *ServerConfig) UnmarshalMapstructure(data any) error { m, ok := data.(map[string]any) if !ok { return fmt.Errorf("expected map[string]any, got %T", data) } // Apply defaults first s.Host = "localhost" s.Port = 8080 // Override with provided values if host, ok := m["host"].(string); ok { s.Host = host } if port, ok := m["port"].(int); ok { s.Port = port } return nil } func main() { input := map[string]any{ "host": "example.com", // port intentionally omitted to use default } var result ServerConfig err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("Host: %s, Port: %d", result.Host, result.Port) // Output: Host: example.com, Port: 8080 } ``` -------------------------------- ### Apply TextUnmarshallerHookFunc for TextUnmarshaler Types Source: https://context7.com/go-viper/mapstructure/llms.txt Use TextUnmarshallerHookFunc to decode string values into types that implement the encoding.TextUnmarshaler interface, such as net/url.URL. ```go package main import ( "fmt" "net/url" "github.com/go-viper/mapstructure/v2" ) type ServiceConfig struct { Endpoint *url.URL } func main() { input := map[string]any{ "endpoint": "https://api.example.com/v1", } var result ServiceConfig config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.TextUnmarshallerHookFunc(), mapstructure.StringToURLHookFunc(), ), Result: &result, } decoder, err := mapstructure.NewDecoder(config) if err != nil { panic(err) } err = decoder.Decode(input) if err != nil { panic(err) } fmt.Printf("Endpoint Host: %s, Path: %s", result.Endpoint.Host, result.Endpoint.Path) // Output: Endpoint Host: api.example.com, Path: /v1 } ``` -------------------------------- ### Weakly Decode Map to Struct with Automatic Type Conversions Source: https://context7.com/go-viper/mapstructure/llms.txt WeakDecode automatically converts types like string to int, number to string, and empty maps to empty slices. This is useful for lenient data ingestion. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int Emails []string } func main() { input := map[string]any{ "name": 123, // number => string "age": "42", // string => number "emails": map[string]any{}, // empty map => empty array } var result Person err := mapstructure.WeakDecode(input, &result) if err != nil { panic(err) } fmt.Printf("%#v", result) // Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}} } ``` -------------------------------- ### Struct to Map Decoding with mapstructure Source: https://context7.com/go-viper/mapstructure/llms.txt Utilize mapstructure to decode data from a struct into a map. This supports reverse decoding, which is beneficial for serialization processes where a map representation is required. Custom field names defined with `mapstructure` tags are respected. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int Email string `mapstructure:"email_address"` } func main() { input := Person{ Name: "Alice", Age: 30, Email: "alice@example.com", } result := make(map[string]any) err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("Name: %v, Age: %v, Email key: %v", result["Name"], result["Age"], result["email_address"]) // Output: Name: Alice, Age: 30, Email key: alice@example.com } ``` -------------------------------- ### Decode Map to Struct using mapstructure Source: https://context7.com/go-viper/mapstructure/llms.txt Use the Decode function to convert a map[string]any into a Go struct. Ensure the struct pointer is passed as the second argument. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int Emails []string Extra map[string]string } func main() { input := map[string]any{ "name": "Mitchell", "age": 91, "emails": []string{"one", "two", "three"}, "extra": map[string]string{ "twitter": "mitchellh", }, } var result Person err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("%#v", result) // Output: mapstructure.Person{Name:"Mitchell", Age:91, Emails:[]string{"one", "two", "three"}, Extra:map[string]string{"twitter":"mitchellh"}} } ``` -------------------------------- ### Rename Struct Fields using mapstructure Tag Source: https://context7.com/go-viper/mapstructure/llms.txt Utilize the `mapstructure` struct tag to map incoming map keys to different struct field names. This is essential for handling external data with varying key names. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string `mapstructure:"person_name"` Age int `mapstructure:"person_age"` } func main() { input := map[string]any{ "person_name": "Mitchell", "person_age": 91, } var result Person err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("%#v", result) // Output: mapstructure.Person{Name:"Mitchell", Age:91} } ``` -------------------------------- ### Flatten Embedded Structs with Squash Tag Source: https://context7.com/go-viper/mapstructure/llms.txt Use the `squash` tag option to flatten embedded struct fields into the parent struct. This allows direct access to nested fields without requiring nested map keys. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Family struct { LastName string } type Location struct { City string } type Person struct { Family `mapstructure:",squash"` Location `mapstructure:",squash"` FirstName string } func main() { input := map[string]any{ "FirstName": "Mitchell", "LastName": "Hashimoto", "City": "San Francisco", } var result Person err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City) // Output: Mitchell Hashimoto, San Francisco } ``` -------------------------------- ### Capture Unused Keys with Remain Tag Source: https://context7.com/go-viper/mapstructure/llms.txt Utilize the `remain` tag option to collect all map keys that do not map to struct fields into a designated map field. This is useful for handling dynamic or extra properties in your data. ```go package main import ( "fmt" "github.com/go-viper/mapstructure/v2" ) type Person struct { Name string Age int Other map[string]any `mapstructure:",remain"` } func main() { input := map[string]any{ "name": "Mitchell", "age": 91, "email": "mitchell@example.com", "phone": "555-1234", } var result Person err := mapstructure.Decode(input, &result) if err != nil { panic(err) } fmt.Printf("Name: %s, Age: %d\n", result.Name, result.Age) fmt.Printf("Other: %v\n", result.Other) // Output: // Name: Mitchell, Age: 91 // Other: map[email:mitchell@example.com phone:555-1234] } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.