Documentation
¶
Overview ¶
Package object ports the "Object" category of the npm lodash library to Go, providing the map- and structure-oriented helpers such as Keys, Values, Entries, Pick, Omit, MapKeys, MapValues, Invert, Assign, Merge, Defaults, Get, Set, Has, Unset, Update, Clone, CloneDeep, IsEqual and Transform. In JavaScript these operate on plain objects; here they operate on Go maps and, for the dynamically-typed path and merge helpers, on the any-typed tree of map[string]any and []any values that a decoded JSON document produces. The package depends only on the Go standard library.
Reach for this package when you are manipulating decoded JSON or other loosely-typed nested data and want the ergonomic, batteries-included vocabulary that lodash offers on the front end: extracting a subset of keys, re-keying or re-mapping values, deeply merging configuration layers, reading or writing a value several levels down by a single "a.b.c" path, or comparing two trees for structural equality. The statically-typed helpers (Keys, Values, Entries, Pick, Omit, MapKeys, MapValues, Invert, FindKey and friends) are written with Go generics so they work over any comparable key type and any value type without reflection or boxing.
The functions divide into two families by how they are typed. The collection helpers are generic over [K comparable, V any] and simply iterate the map to build a fresh result; Pick copies only the requested keys that are present, Omit copies everything except a drop-set of keys, and the *By variants take a predicate or iteratee instead of an explicit key list. The dynamic helpers operate on any: Get, Set, Has, Unset and Update accept dot-notation paths such as "a.b.c", splitting on "." and walking the tree one segment at a time. A numeric segment indexes into a []any slice, so the path "a.0.b" descends into the first element of the slice stored under key "a"; Set creates the intermediate map or slice containers on demand (choosing a slice when the next segment is numeric) and grows slices with nil padding as needed.
Edge-case semantics follow lodash closely. Get returns the supplied defaultValue (or nil) whenever any segment along the path is missing, out of range, or the resolved value is itself nil. Defaults and DefaultsDeep only fill keys that are absent or hold nil, never overwriting an existing non-nil value, and DefaultsDeep recurses into nested maps while deep-cloning the values it copies in. Merge recursively merges nested maps key by key and nested slices index by index, skipping nil source values, whereas Assign is a shallow overwrite. CloneDeep recursively copies map and slice containers so that later mutation cannot reach the original, and IsEqual compares trees structurally, guarding against panics from uncomparable scalar types by treating them as unequal. Passing a nil destination to the mutating helpers (Assign, Merge, Defaults, DefaultsDeep, Transform) allocates a fresh map.
Parity with Node's lodash is close in behavior but adapted to Go's type system and runtime. The most visible difference is ordering: Go map iteration is randomized, so Keys, Values, Entries, MapKeys and the For* iterators do not preserve insertion order the way lodash does, and functions whose result would otherwise be order-dependent take deliberate steps to stay deterministic (FindKey examines keys in sorted order). There is no notion of JavaScript "undefined" versus a present-but-null value, so nil stands in for both; Unset deletes a map key but, matching lodash's array delete, only nils out a slice element rather than shifting the slice. Symbol keys, prototype chains, getters and lodash's customizer callbacks have no equivalent here.
Index ¶
- func Assign(dst map[string]any, sources ...map[string]any) map[string]any
- func AssignWith[K comparable, V any](dst, src map[K]V, customizer func(dstVal, srcVal V, key K) V) map[K]V
- func At[K comparable, V any](m map[K]V, keys ...K) []V
- func Clone(value any) any
- func CloneDeep(value any) any
- func Defaults(dst map[string]any, sources ...map[string]any) map[string]any
- func DefaultsDeep(dst map[string]any, sources ...map[string]any) map[string]any
- func EveryEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) bool
- func FindEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) (K, V, bool)
- func FindKey[V any](m map[string]V, predicate func(value V, key string) bool) (string, bool)
- func ForIn(m map[string]any, iteratee func(value any, key string) bool)
- func ForOwn(m map[string]any, iteratee func(value any, key string) bool)
- func FromEntries[K comparable, V any](pairs []Pair[K, V]) map[K]V
- func Get(root any, path string, defaultValue ...any) any
- func Has(root any, path string) bool
- func Invert[K comparable, V comparable](m map[K]V) map[V]K
- func InvertBy[K comparable, V any, R comparable](m map[K]V, iteratee func(value V) R) map[R][]K
- func IsEqual(a, b any) bool
- func Keys[K comparable, V any](m map[K]V) []K
- func MapKeys[K comparable, V any, R comparable](m map[K]V, iteratee func(value V, key K) R) map[R]V
- func MapValues[K comparable, V any, R any](m map[K]V, iteratee func(value V, key K) R) map[K]R
- func Merge(dst map[string]any, sources ...map[string]any) map[string]any
- func Omit[K comparable, V any](m map[K]V, keys ...K) map[K]V
- func OmitBy[K comparable, V any](m map[K]V, predicate func(value V, key K) bool) map[K]V
- func Pick[K comparable, V any](m map[K]V, keys ...K) map[K]V
- func PickBy[K comparable, V any](m map[K]V, predicate func(value V, key K) bool) map[K]V
- func ReduceEntries[K comparable, V any, R any](m map[K]V, iteratee func(acc R, key K, value V) R, accumulator R) R
- func Set(root any, path string, value any) any
- func SomeEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) bool
- func Transform(m map[string]any, ...) map[string]any
- func Unset(root any, path string) bool
- func Update(root any, path string, updater func(current any) any) any
- func Values[K comparable, V any](m map[K]V) []V
- type Pair
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Assign ¶
Assign copies the own enumerable keys of each source into dst, with later sources overwriting earlier ones. It mutates and returns dst. This is a shallow copy (lodash's assign / Object.assign).
func AssignWith ¶ added in v0.4.0
func AssignWith[K comparable, V any](dst, src map[K]V, customizer func(dstVal, srcVal V, key K) V) map[K]V
AssignWith merges src into a copy of dst, resolving each key with customizer, which receives the destination and source values (the destination value is the zero value of V when the key is only in src) and returns the value to store. It mirrors lodash.assignWith and never mutates its arguments.
func At ¶ added in v0.4.0
func At[K comparable, V any](m map[K]V, keys ...K) []V
At returns the values of m at the given keys, in the order the keys are supplied. A key that is not present yields the zero value of V. It mirrors lodash.at for a map.
func Clone ¶
Clone returns a shallow copy of value. For maps and slices a new top-level container is allocated but nested values are shared with the original. Scalar values are returned unchanged.
func CloneDeep ¶
CloneDeep returns a deep copy of value, recursively copying nested map[string]any and []any containers so that mutating the result never affects the original. Scalar values are returned unchanged.
func Defaults ¶
Defaults assigns, for each source in sources, the values of keys that are missing (or hold the zero value equivalent of "undefined") in dst. Existing, non-nil keys in dst are preserved. It mutates and returns dst.
Faithful to lodash, only the first value encountered for a key is used, and keys already present with a non-nil value are left untouched.
func DefaultsDeep ¶
DefaultsDeep is like Defaults except it recurses into nested map[string]any values, filling in missing keys at every depth. It mutates and returns dst.
func EveryEntry ¶ added in v0.4.0
func EveryEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) bool
EveryEntry reports whether predicate returns true for every entry of m. It returns true for an empty map.
func FindEntry ¶ added in v0.4.0
func FindEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) (K, V, bool)
FindEntry returns an arbitrary entry of m for which predicate is true, along with true; if no entry matches it returns zero values and false.
func FindKey ¶
FindKey returns the key of the first entry of m for which predicate returns true, along with true. If no entry matches, it returns the zero key and false.
Because Go map iteration order is randomized, callers that need a deterministic result over multiple matches should not rely on which matching key is returned. To keep FindKey predictable in the common case, keys are examined in sorted order.
Example ¶
ExampleFindKey returns the key of the first entry satisfying a predicate. Because Go map iteration order is randomized, FindKey examines keys in sorted order to keep its result deterministic when several entries would match. It returns the found key together with true, or the zero key and false when nothing matches. The predicate receives both the value and the key. Here it locates the key whose value equals 2.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
m := map[string]int{"a": 1, "b": 2, "c": 3}
key, ok := object.FindKey(m, func(v int, k string) bool { return v == 2 })
fmt.Println(key, ok)
}
Output: b true
func ForIn ¶
ForIn iterates over the entries of m, invoking iteratee for each. If iteratee returns false, iteration stops early. (For plain maps ForIn and ForOwn behave identically; both are provided to match lodash.)
func ForOwn ¶
ForOwn iterates over the own enumerable entries of m, invoking iteratee for each. If iteratee returns false, iteration stops early.
func FromEntries ¶
func FromEntries[K comparable, V any](pairs []Pair[K, V]) map[K]V
FromEntries builds a map from a slice of Pair. Later pairs overwrite earlier ones that share a key.
func Get ¶
Get retrieves the value at the given dot-notation path within root. If any segment along the path is missing, the provided defaultValue is returned (or nil if none is supplied). Numeric segments index into []any slices.
Example ¶
ExampleGet demonstrates reading a deeply nested value by a single dot-notation path. The root is the kind of any-typed tree that decoding a JSON document produces, mixing map[string]any and []any containers. A numeric path segment such as "0" indexes into a slice, so "a.b.0.c" walks a map, a slice, and then another map in one call. When any segment along the path is missing or out of range, Get returns the supplied default value instead of panicking. This makes Get a safe way to probe optional configuration values.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
root := map[string]any{
"a": map[string]any{
"b": []any{
map[string]any{"c": 42},
},
},
}
fmt.Println(object.Get(root, "a.b.0.c"))
fmt.Println(object.Get(root, "a.b.5.c", "missing"))
}
Output: 42 missing
func Invert ¶
func Invert[K comparable, V comparable](m map[K]V) map[V]K
Invert returns a new map composed of the inverted keys and values of m. If m contains duplicate values, subsequent values overwrite prior ones.
Example ¶
ExampleInvert swaps keys and values, producing a new map whose keys are the original values. Both the key and value types must be comparable so the result is a valid map. When the source contains duplicate values, later entries overwrite earlier ones, so the inverse may be smaller than the original. Here the values are distinct, so the mapping is one-to-one. The output prints in sorted key order.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
m := map[string]string{"a": "1", "b": "2"}
fmt.Println(object.Invert(m))
}
Output: map[1:a 2:b]
func InvertBy ¶
func InvertBy[K comparable, V any, R comparable](m map[K]V, iteratee func(value V) R) map[R][]K
InvertBy returns a new map composed of keys generated from the results of running each value of m through iteratee. Each key maps to the slice of original keys responsible for generating it.
func IsEqual ¶
IsEqual reports whether a and b are deeply, structurally equal. It compares map[string]any values key by key, []any values element by element, and falls back to == for scalars. Two nil values are equal.
Example ¶
ExampleIsEqual compares two values for deep structural equality. It descends into nested maps and slices, comparing them key by key and element by element, and falls back to == for scalar leaves. Two independently constructed trees with the same shape and contents are reported as equal. This avoids the pitfalls of comparing maps or slices directly, which is not allowed with ==. The comparison is order-independent for maps and order-sensitive for slices.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
a := map[string]any{"x": []any{1, 2}}
b := map[string]any{"x": []any{1, 2}}
fmt.Println(object.IsEqual(a, b))
}
Output: true
func Keys ¶
func Keys[K comparable, V any](m map[K]V) []K
Keys returns the keys of m. The order of the returned slice is not guaranteed (Go map iteration order is randomized).
func MapKeys ¶
func MapKeys[K comparable, V any, R comparable](m map[K]V, iteratee func(value V, key K) R) map[R]V
MapKeys returns a new map with the same values as m but with keys produced by running each entry through iteratee. If iteratee maps two keys to the same result, the last one written wins.
func MapValues ¶
func MapValues[K comparable, V any, R any](m map[K]V, iteratee func(value V, key K) R) map[K]R
MapValues returns a new map with the same keys as m but with values produced by running each entry through iteratee.
Example ¶
ExampleMapValues transforms every value in a map while preserving its keys. The iteratee receives both the value and its key and returns the replacement value, which may be of a different type. This is the map-shaped counterpart of a slice transform and does not mutate the source. Here each integer value is doubled. The result prints deterministically in sorted key order.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
m := map[string]int{"a": 1, "b": 2}
doubled := object.MapValues(m, func(v int, k string) int { return v * 2 })
fmt.Println(doubled)
}
Output: map[a:2 b:4]
func Merge ¶
Merge recursively merges the sources into dst. Nested map[string]any values are merged key by key; nested []any values are merged index by index (as lodash does for array-like objects). Non-mergeable values from a source overwrite the destination unless the source value is nil, in which case the destination is preserved. It mutates and returns dst.
Example ¶
ExampleMerge recursively combines source maps into a destination. Nested maps are merged key by key rather than replaced wholesale, so keys unique to either side survive. This mirrors how lodash deep-merges plain objects and is useful for layering configuration defaults with overrides. Merge mutates and returns the destination map. The nested result prints deterministically because fmt sorts keys at every level.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
dst := map[string]any{"a": map[string]any{"x": 1}}
src := map[string]any{"a": map[string]any{"y": 2}}
merged := object.Merge(dst, src)
fmt.Println(merged)
}
Output: map[a:map[x:1 y:2]]
func Omit ¶
func Omit[K comparable, V any](m map[K]V, keys ...K) map[K]V
Omit returns a new map with the given keys removed from m.
Example ¶
ExampleOmit is the complement of Pick: it copies every entry except the ones whose keys are listed. Like Pick it returns a fresh map and leaves the original untouched. This is handy for stripping sensitive fields such as a password before logging or serializing a record. Listing a key that is not present has no effect. The printed output is deterministic because fmt sorts map keys.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
m := map[string]int{"name": 1, "age": 2, "password": 3}
safe := object.Omit(m, "password")
fmt.Println(safe)
}
Output: map[age:2 name:1]
func OmitBy ¶
func OmitBy[K comparable, V any](m map[K]V, predicate func(value V, key K) bool) map[K]V
OmitBy returns a new map with the entries of m for which predicate returns true removed.
func Pick ¶
func Pick[K comparable, V any](m map[K]V, keys ...K) map[K]V
Pick returns a new map composed of the given keys picked from m. Keys that are not present in m are skipped.
Example ¶
ExamplePick builds a new map containing only a chosen subset of keys. It is the map-shaped analogue of selecting columns from a record, and it never mutates the source map. Keys that are requested but not present in the source are simply skipped rather than added with a zero value. Because Go's fmt package prints map keys in sorted order, the output here is deterministic. Pick is generic, so it works over any comparable key type and any value type.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
m := map[string]int{"name": 1, "age": 2, "email": 3}
picked := object.Pick(m, "name", "email")
fmt.Println(picked)
}
Output: map[email:3 name:1]
func PickBy ¶
func PickBy[K comparable, V any](m map[K]V, predicate func(value V, key K) bool) map[K]V
PickBy returns a new map composed of the entries of m for which predicate returns true.
func ReduceEntries ¶ added in v0.4.0
func ReduceEntries[K comparable, V any, R any](m map[K]V, iteratee func(acc R, key K, value V) R, accumulator R) R
ReduceEntries folds the entries of m into an accumulator using iteratee. Because map iteration order is unspecified, use it only with an associative, commutative reduction (such as summing values). It mirrors lodash.reduce over an object.
func Set ¶
Set sets the value at the given dot-notation path within root, creating intermediate map[string]any containers as needed. Numeric segments index into (and, when necessary, grow) []any slices. It returns the (possibly replaced) root so callers can capture a newly created container.
Example ¶
ExampleSet writes a value at a dot-notation path, creating the intermediate containers as it goes. Passing a nil root lets Set allocate the top-level container for you, choosing a map or a slice based on whether the first segment is numeric. Here the path "a.b.c" is entirely non-numeric, so nested maps are created at each level. Set returns the (possibly newly allocated) root so the caller can capture it. Reading the value back with Get confirms the write landed where expected.
package main
import (
"fmt"
"github.com/malcolmston/express/lodash/object"
)
func main() {
root := object.Set(nil, "a.b.c", 10)
fmt.Println(object.Get(root, "a.b.c"))
}
Output: 10
func SomeEntry ¶ added in v0.4.0
func SomeEntry[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) bool
SomeEntry reports whether predicate returns true for at least one entry of m. It returns false for an empty map.
func Transform ¶
func Transform(m map[string]any, iteratee func(acc map[string]any, value any, key string) bool, accumulator map[string]any) map[string]any
Transform is a variant of Reduce for objects. It runs each entry of m through iteratee, threading an accumulator that iteratee mutates in place. If iteratee returns false, iteration stops early. The accumulator is returned.
func Unset ¶
Unset removes the value at the given dot-notation path from root. It reports whether a value was removed. Numeric segments index into []any slices; for slices the element is set to nil (lodash-style delete) rather than removed.
func Update ¶
Update is like Set except the new value is produced by running the current value at path (or nil if absent) through updater. It returns the (possibly replaced) root.
func Values ¶
func Values[K comparable, V any](m map[K]V) []V
Values returns the values of m. The order of the returned slice is not guaranteed.
Types ¶
type Pair ¶
type Pair[K comparable, V any] struct { // Key is the map key of the entry. Key K // Value is the map value associated with Key. Value V }
Pair is a single key/value entry, as produced by Entries.
func Entries ¶
func Entries[K comparable, V any](m map[K]V) []Pair[K, V]
Entries returns the key/value pairs of m as a slice of Pair. It is the generic equivalent of lodash's toPairs.
func ToPairs ¶
func ToPairs[K comparable, V any](m map[K]V) []Pair[K, V]
ToPairs is an alias for Entries, matching lodash's naming.