anyx - Interface{} Helpers

Overview

The anyx module provides type-safe operations on interface{} values with convenient methods for accessing and converting data. It wraps sync.Map for thread-safe operations.

Core Type

MapAny

Thread-safe map with type-safe accessors.

type MapAny struct {
    data *sync.Map
    cut  *atomic.Bool
    seq  *atomic.String
}

Constructors

NewMap()

Create a new MapAny from a map.

func NewMap(m map[string]interface{}) *MapAny

Example:

m := anyx.NewMap(map[string]interface{}{
    "name":  "John",
    "age":   30,
    "email": "john@example.com",
})

NewMapWithJson()

Create a new MapAny from JSON bytes.

func NewMapWithJson(s []byte) (*MapAny, error)

Example:

data := []byte(`{"name":"John","age":30}`)
m, err := anyx.NewMapWithJson(data)
if err != nil {
    log.Errorf("Failed to parse JSON: %v", err)
}

NewMapWithYaml()

Create a new MapAny from YAML bytes.

func NewMapWithYaml(s []byte) (*MapAny, error)

Example:

data := []byte("name: John\nage: 30")
m, err := anyx.NewMapWithYaml(data)
if err != nil {
    log.Errorf("Failed to parse YAML: %v", err)
}

NewMapWithAny()

Create a new MapAny from any value.

func NewMapWithAny(s interface{}) (*MapAny, error)

Example:

m, err := anyx.NewMapWithAny(struct {
    Name string
    Age  int
}{Name: "John", Age: 30})

Configuration Methods

EnableCut()

Enable nested key access with separator.

func (p *MapAny) EnableCut(seq string) *MapAny

Parameters:

  • seq - Separator string (e.g., ".", "/")

Returns:

  • MapAny instance for chaining

Example:

m := anyx.NewMap(map[string]interface{}{
    "user": map[string]interface{}{
        "name": "John",
        "email": "john@example.com",
    },
})

m.EnableCut(".")
name := m.GetString("user.name")  // "John"

DisableCut()

Disable nested key access.

func (p *MapAny) DisableCut() *MapAny

Example:

m.EnableCut(".").DisableCut()

Basic Operations

Set()

Set a key-value pair.

func (p *MapAny) Set(key string, value interface{})

Example:

m := anyx.NewMap(nil)
m.Set("name", "John")
m.Set("age", 30)
m.Set("active", true)

Get()

Get a value by key.

func (p *MapAny) Get(key string) (interface{}, error)

Returns:

  • Value if key exists
  • ErrNotFound if key does not exist

Example:

value, err := m.Get("name")
if err != nil {
    log.Errorf("Key not found: %v", err)
} else {
    fmt.Printf("Name: %v\n", value)
}

Exists()

Check if a key exists.

func (p *MapAny) Exists(key string) bool

Example:

if m.Exists("name") {
    fmt.Println("Name exists")
}

Type-Safe Getters

GetBool()

Get value as boolean.

func (p *MapAny) GetBool(key string) bool

Example:

m.Set("active", true)
active := m.GetBool("active")  // true

GetInt()

Get value as int.

func (p *MapAny) GetInt(key string) int

Example:

m.Set("age", 30)
age := m.GetInt("age")  // 30

GetInt32(), GetInt64()

Get value as int32 or int64.

func (p *MapAny) GetInt32(key string) int32
func (p *MapAny) GetInt64(key string) int64

GetUint16(), GetUint32(), GetUint64()

Get value as unsigned integer.

func (p *MapAny) GetUint16(key string) uint16
func (p *MapAny) GetUint32(key string) uint32
func (p *MapAny) GetUint64(key string) uint64

GetFloat64()

Get value as float64.

func (p *MapAny) GetFloat64(key string) float64

Example:

m.Set("price", 19.99)
price := m.GetFloat64("price")  // 19.99

GetString()

Get value as string.

func (p *MapAny) GetString(key string) string

Example:

m.Set("name", "John")
name := m.GetString("name")  // "John"

GetBytes()

Get value as []byte.

func (p *MapAny) GetBytes(key string) []byte

GetMap()

Get value as nested MapAny.

func (p *MapAny) GetMap(key string) *MapAny

Example:

m.Set("user", map[string]interface{}{
    "name": "John",
    "email": "john@example.com",
})

user := m.GetMap("user")
name := user.GetString("name")  // "John"

GetSlice()

Get value as []interface{}.

func (p *MapAny) GetSlice(key string) []interface{}

Example:

m.Set("tags", []interface{}{"go", "utils", "library"})
tags := m.GetSlice("tags")  // []interface{}{"go", "utils", "library"}

GetStringSlice()

Get value as []string.

func (p *MapAny) GetStringSlice(key string) []string

Example:

m.Set("tags", []interface{}{"go", "utils"})
tags := m.GetStringSlice("tags")  // []string{"go", "utils"}

GetInt64Slice()

Get value as []int64.

func (p *MapAny) GetInt64Slice(key string) []int64

GetUint32Slice()

Get value as []uint32.

func (p *MapAny) GetUint32Slice(key string) []uint32

GetUint64Slice()

Get value as []uint64.

func (p *MapAny) GetUint64Slice(key string) []uint64

Conversion Methods

ToMap()

Convert to standard map[string]interface{}.

func (p *MapAny) ToMap() map[string]interface{}

Example:

m := anyx.NewMap(map[string]interface{}{
    "name": "John",
    "age":  30,
})

stdMap := m.ToMap()
// stdMap is map[string]interface{}{"name": "John", "age": 30}

ToSyncMap()

Convert to *sync.Map.

func (p *MapAny) ToSyncMap() *sync.Map

Clone()

Create a copy of MapAny.

func (p *MapAny) Clone() *MapAny

Example:

original := anyx.NewMap(map[string]interface{}{
    "name": "John",
})

copy := original.Clone()
copy.Set("name", "Jane")
// original.GetString("name") == "John"
// copy.GetString("name") == "Jane"

Iteration

Range()

Iterate over all key-value pairs.

func (p *MapAny) Range(f func(key, value interface{}) bool)

Example:

m.Range(func(key, value interface{}) bool {
    fmt.Printf("%s: %v\n", key, value)
    return true  // Continue iteration
})

Usage Patterns

Configuration Management

func loadConfig() *anyx.MapAny {
    data, _ := os.ReadFile("config.json")
    cfg, _ := anyx.NewMapWithJson(data)
    return cfg
}

func getConfig(cfg *anyx.MapAny, key string) string {
    return cfg.GetString(key)
}

func setConfig(cfg *anyx.MapAny, key string, value string) {
    cfg.Set(key, value)
}

Nested Data Access

m := anyx.NewMap(map[string]interface{}{
    "database": map[string]interface{}{
        "host": "localhost",
        "port": 5432,
        "credentials": map[string]interface{}{
            "username": "admin",
            "password": "secret",
        },
    },
})

m.EnableCut(".")
host := m.GetString("database.host")  // "localhost"
port := m.GetInt("database.port")  // 5432
username := m.GetString("database.credentials.username")  // "admin"

Type Conversion

func processData(data *anyx.MapAny) {
    name := data.GetString("name")
    age := data.GetInt("age")
    active := data.GetBool("active")
    price := data.GetFloat64("price")
    tags := data.GetStringSlice("tags")
    
    fmt.Printf("Name: %s, Age: %d, Active: %v\n", name, age, active)
    fmt.Printf("Price: %.2f, Tags: %v\n", price, tags)
}

Thread-Safe Operations

var cache = anyx.NewMap(nil)

func getFromCache(key string) (interface{}, bool) {
    val, err := cache.Get(key)
    if err == anyx.ErrNotFound {
        return nil, false
    }
    return val, true
}

func setCache(key string, value interface{}) {
    cache.Set(key, value)
}

Best Practices

Error Handling

// Good: Handle not found errors
value, err := m.Get("key")
if err != nil {
    if err == anyx.ErrNotFound {
        fmt.Println("Key not found")
    } else {
        fmt.Printf("Error: %v\n", err)
    }
}

// Good: Use Exists() before Get
if m.Exists("key") {
    value, _ := m.Get("key")
    fmt.Printf("Value: %v\n", value)
}

Type Safety

// Good: Use type-safe getters
age := m.GetInt("age")
name := m.GetString("name")
active := m.GetBool("active")

// Avoid: Manual type assertions
value, _ := m.Get("age")
age, ok := value.(int)
if !ok {
    // Handle type mismatch
}

Nested Access

// Good: Enable cut for nested access
m.EnableCut(".")
value := m.GetString("user.profile.name")

// Alternative: Chain GetMap()
user := m.GetMap("user")
profile := user.GetMap("profile")
name := profile.GetString("name")