Documentation ¶
Overview ¶
Package geko provides GEneric Keep Order types.
It's mainly used to solve the issue that in some scenarios, the field order in JSON object is meaningful, but when unmarshal into a normal map, these information will be lost. See golang/go#27179.
Provided types ¶
- Map, and it's type alias Object, to replace map.
- Pairs, and it's type alias ObjectItems, to replace map, when you need to keep all values of duplicated key.
- List, and it's type alias Array to replace slice.
- Any type, to replace the interface{}, it will use types above to do JSON unmarshal.
The JSONUnmarshal function is a shorthand for defined an Any and unmarshal data into it.
Example of JSON processing ¶
result, _ := geko.JSONUnmarshal([]byte(`{"b": 1, "a": 2, "b": 3}`)) object := result.(geko.ObjectItems) output, _ := json.Marshal(object) fmt.Println(string(output)) // {"b":1,"a:2","b":3}
If you do not want duplicated key in result, you can use Pairs.ToMap, or use UseObject to let JSONUnmarshal do it for you:
result, _ := geko.JSONUnmarshal( []byte(`{"b": 1, "a": 2, "b": 3}`), geko.UseObject(), ) object, _ := result.(geko.Object) object.Keys() // => ["b", "a"] output, _ := json.Marshal(object) fmt.Println(string(output)) // {"b":3,"a:2"}
The UseObject option will make it use Object to unmarshal JSON object, instead of ObjectItems. Object will automatically deal with duplicated key for you. Maybe you think "b" should be 1, or "b" should appear after "a", these behavior can be adjusted by using ObjectOnDuplicatedKey with DuplicatedKeyStrategy.
JSONUnmarshal supports all JSON item, that's why it returns any. You can directly unmarshal into a Object/ObjectItems or Array, if the type of input data is determined:
var arr geko.Array // or geko.Object for JSON object _ := json.Unmarshal([]byte(`[1, 2, {"one": 1}, false]`), &arr) object, _ := arr.Get(2).(geko.ObjectItems) object.GetFirstOrZeroValue("one") // => 1
But you can't customize DecodeOptions when doing this, it will always use default options.
Use container type directly ¶
Outside of JSON processing, these types can also be used simply as generic container types with insertion order preservation feature:
m := geko.NewMap[int, string]() m.Set(1, "one") m.Set(3, "three") m.Set(2, "two") m.Get(3) // "three", true m.GetValueByIndex(1) // "three"
There are many API for Map, List and Pairs, see their document for details.
Index ¶
- func JSONUnmarshal(data []byte, option ...DecodeOption) (any, error)
- type Any
- type Array
- type DecodeOption
- type DecodeOptions
- type DuplicatedKeyStrategy
- type List
- type Map
- func (m *Map[K, V]) Add(key K, value V)
- func (m *Map[K, V]) Append(pairs ...Pair[K, V])
- func (m *Map[K, V]) Clear()
- func (m *Map[K, V]) Delete(key K)
- func (m *Map[K, V]) DeleteByIndex(index int)
- func (m *Map[K, V]) DuplicatedKeyStrategy() DuplicatedKeyStrategy
- func (m *Map[K, V]) Filter(pred PairFilterFunc[K, V])
- func (m *Map[K, V]) Get(key K) (V, bool)
- func (m *Map[K, V]) GetByIndex(index int) Pair[K, V]
- func (m *Map[K, V]) GetKeyByIndex(index int) K
- func (m *Map[K, V]) GetOrZeroValue(key K) V
- func (m *Map[K, V]) GetValueByIndex(index int) V
- func (m *Map[K, V]) Has(key K) bool
- func (m *Map[K, V]) Keys() []K
- func (m *Map[K, V]) Len() int
- func (m Map[K, V]) MarshalJSON() ([]byte, error)
- func (m *Map[K, V]) Pairs() *Pairs[K, V]
- func (m *Map[K, V]) Set(key K, value V)
- func (m *Map[K, V]) SetDuplicatedKeyStrategy(strategy DuplicatedKeyStrategy)
- func (m *Map[K, V]) Sort(lessFunc PairLessFunc[K, V])
- func (m *Map[K, V]) UnmarshalJSON(data []byte) error
- func (m *Map[K, V]) Values() []V
- type Object
- type ObjectItems
- type Pair
- type PairFilterFunc
- type PairLessFunc
- type Pairs
- func (ps *Pairs[K, V]) Add(key K, value V)
- func (ps *Pairs[K, V]) Append(pairs ...Pair[K, V])
- func (ps *Pairs[K, V]) Clear()
- func (ps *Pairs[K, V]) Count(key K) int
- func (ps *Pairs[K, V]) Dedup(strategy DuplicatedKeyStrategy)
- func (ps *Pairs[K, V]) Delete(key K)
- func (ps *Pairs[K, V]) DeleteByIndex(index int)
- func (ps *Pairs[K, V]) Filter(pred PairFilterFunc[K, V])
- func (ps *Pairs[K, V]) Get(key K) []V
- func (ps *Pairs[K, V]) GetByIndex(index int) Pair[K, V]
- func (ps *Pairs[K, V]) GetFirstOrZeroValue(key K) (value V)
- func (ps *Pairs[K, V]) GetKeyByIndex(index int) K
- func (ps *Pairs[K, V]) GetLastOrZeroValue(key K) (value V)
- func (ps *Pairs[K, V]) GetValueByIndex(index int) V
- func (ps *Pairs[K, V]) Has(key K) bool
- func (ps *Pairs[K, V]) Keys() []K
- func (ps *Pairs[K, V]) Len() int
- func (ps Pairs[K, V]) MarshalJSON() ([]byte, error)
- func (ps *Pairs[K, V]) SetByIndex(index int, key K, value V)
- func (ps *Pairs[K, V]) SetKeyByIndex(index int, key K)
- func (ps *Pairs[K, V]) SetValueByIndex(index int, value V)
- func (ps *Pairs[K, V]) Sort(lessFunc PairLessFunc[K, V])
- func (ps *Pairs[K, V]) ToMap(strategy DuplicatedKeyStrategy) *Map[K, V]
- func (ps *Pairs[K, V]) UnmarshalJSON(data []byte) error
- func (ps *Pairs[K, V]) Values() []V
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func JSONUnmarshal ¶
func JSONUnmarshal(data []byte, option ...DecodeOption) (any, error)
JSONUnmarshal is A convenience function for unmarshal JSON data into an Any and get the inner any value.
Types ¶
type Any ¶
type Any struct { Value any Opts DecodeOptions }
Any is a wrapper for an any value. But when unmarshal, it uses our Object/ObjectItems and Array when meet JSON object and array.
So the type of Any.Value after a json.Unmarshal can be: bool, float64/json.Number, string, nil, Object/ObjectItems, Array.
You can customize the unmarshal behavior by setting Any.Opts before call json.Unmarshal.
Notice: Usually you don't need to use this type directly. And, do not use this type on the value type parameter of the Map, Pairs or List. Because container types already handles standard any type specially, doing so will not only has no benefit, but also lose performance.
func (Any) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface.
You should not call this directly, use json.Marshal instead.
func (*Any) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler interface.
You shouldn't call this directly, use json.Unmarshal/JSONUnmarshal instead.
type Array ¶
Array is a List whose type parameters are specialized as any, used to represent dynamic array in JSON.
type DecodeOption ¶
type DecodeOption func(opts *DecodeOptions)
DecodeOption is atom/modifier of DecodeOptions.
func ObjectOnDuplicatedKey ¶
func ObjectOnDuplicatedKey(strategy DuplicatedKeyStrategy) DecodeOption
ObjectOnDuplicatedKey set the strategy when there are duplicated key in JSON object. Only effect when UseObject is applied.
See document of DuplicatedKeyStrategy and its enum value for details.
func UseNumber ¶
func UseNumber(v bool) DecodeOption
UseNumber will enable or disable using json.Number for json number.
func UseObject ¶
func UseObject() DecodeOption
UseObject will change unmarshal behavior to using Object for JSON object.
See also: ObjectOnDuplicatedKey, UseObjectItems.
func UseObjectItems ¶
func UseObjectItems() DecodeOption
UseObjectItems will change unmarshal behavior (back) to using ObjectItems for JSON object.
See also: UseObject.
type DecodeOptions ¶
type DecodeOptions struct {
// contains filtered or unexported fields
}
DecodeOptions are options for controlling the behavior of Any unmarshaling.
Zero value(default value) of it is:
- Do not use json.Number for JSON number
- Uses ObjectItems for JSON object.
See also: CreateDecodeOptions, UseNumber, UseObjectItems, UseObject, ObjectOnDuplicatedKey.
func CreateDecodeOptions ¶
func CreateDecodeOptions(option ...DecodeOption) DecodeOptions
CreateDecodeOptions creates a DecodeOptions by apply all option to the default decode option.
func (*DecodeOptions) Apply ¶
func (opts *DecodeOptions) Apply(option ...DecodeOption)
Apply option to current options.
type DuplicatedKeyStrategy ¶
type DuplicatedKeyStrategy uint8
DuplicatedKeyStrategy controls the behavior of Map.Add when meet a duplicate key. Default strategy is UpdateValueKeepOrder.
If you want store all values of duplicated key, use Pairs instead.
const ( // UpdateValueKeepOrder will use new value, but do not change key order. // // {"a": 1, "b": 2, "a": 3} => {"a": 3, "b": 2} // // This is the default strategy. UpdateValueKeepOrder DuplicatedKeyStrategy = iota // UpdateValueUpdateOrder will use new value, and move the key to last. // // {"a": 1, "b": 2, "a": 3} => {"b": 2, "a": 3} UpdateValueUpdateOrder // KeepValueUpdateOrder will keep the value not change, but move the key to // last. // // {"a": 1, "b": 2, "a": 3} => {"b": 2, "a": 1} KeepValueUpdateOrder // Ignore will do nothing, keeps old key order and value. // // {"a": 1, "b": 2, "a": 3} => {"a": 1, "b": 2} Ignore )
type List ¶
type List[T any] struct { List []T }
List is wrapper type of a normal slice.
If T is any, will use ObjectItems from this package to store JSON object, use Array to store JSON array, instead of normal map[string]any and []any.
If T is a concrete type, the behavior is same as a normal slice.
func NewListFrom ¶
NewListFrom create a List from a slice.
func NewListWithCapacity ¶
NewListWithCapacity create a new empty List, but init with some capacity, for optimize memory allocation.
func (List[T]) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface.
You should not call this directly, use json.Marshal instead.
func (*List[T]) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler interface.
You should not call this directly, use json.Marshal instead.
type Map ¶
type Map[K comparable, V any] struct { // contains filtered or unexported fields }
Map is a map, in which the kv pairs will keep order of their insertion.
In JSON unmarshal, it will use the order of appearance in input JSON data, and marshal output will use the same order.
When unmarshal from JSON into a Object, all JSON object will be stored in Object, all JSON array will be stored in Array, instead of normal map[string]any and []any from std lib.
You can use Map.SetDuplicatedKeyStrategy before call json.Unmarshal to control the behavior when object has duplicated key in your JSON string data.
If you can't make sure the outmost item is object, try JSONUnmarshal.
Example ¶
package main import ( "fmt" "github.com/7sDream/geko" ) func main() { m := geko.NewMap[string, int]() m.Set("one", 1) m.Set("three", 2) m.Set("two", 2) m.Set("three", 3) // set always do not change order of existed key, so "three" will stay ahead of "two". m.Set("four", 0) m.Set("five", 5) m.SetDuplicatedKeyStrategy(geko.UpdateValueUpdateOrder) m.Add("four", 4) // Add will follow DuplicatedKeyStrategy, so now four is last key, and it's value is 4 for i, length := 0, m.Len(); i < length; i++ { pair := m.GetByIndex(i) fmt.Printf("%s: %d\n", pair.Key, pair.Value) } }
Output: one: 1 three: 3 two: 2 five: 5 four: 4
func NewMapWithCapacity ¶
func NewMapWithCapacity[K comparable, V any](capacity int) *Map[K, V]
NewMapWithCapacity likes NewMap, but init the inner container with a capacity to optimize memory allocate.
func (*Map[K, V]) Add ¶
func (m *Map[K, V]) Add(key K, value V)
Add a key value pair.
If the key is already exist in map, the behavior is controlled by Map.DuplicatedKeyStrategy.
func (*Map[K, V]) Append ¶
Append a series of kv pairs into map.
The effect is consistent with calling Map.Add(k, v) multi times.
func (*Map[K, V]) Delete ¶
func (m *Map[K, V]) Delete(key K)
Delete a item by key.
Performance: causes O(n) operation, avoid heavy use.
func (*Map[K, V]) DeleteByIndex ¶
DeleteByIndex delete a item by it's index in order.
You should make sure 0 <= i < Len(), panic if out of bound.
Performance: causes O(n) operation, avoid heavy use.
func (*Map[K, V]) DuplicatedKeyStrategy ¶
func (m *Map[K, V]) DuplicatedKeyStrategy() DuplicatedKeyStrategy
DuplicatedKeyStrategy get current strategy when Map.Add with a duplicated key.
See document of DuplicatedKeyStrategy and its enum value for detail.
func (*Map[K, V]) Filter ¶
func (m *Map[K, V]) Filter(pred PairFilterFunc[K, V])
Filter remove all item which make pred func return false.
Performance: O(n) operation. More efficient then Map.GetByIndex + Map.DeleteByIndex in a loop, which is O(n^2).
func (*Map[K, V]) Get ¶
Get a value by key. The second return value tells if the key exists. If not, first return value will be zero value of type V.
func (*Map[K, V]) GetByIndex ¶
GetByIndex get the key and value by index of key order.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Map[K, V]) GetKeyByIndex ¶
GetKeyByIndex get key by index of key order.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Map[K, V]) GetOrZeroValue ¶
func (m *Map[K, V]) GetOrZeroValue(key K) V
GetOrZeroValue return value by key, or the zero value of type V if key not exist.
func (*Map[K, V]) GetValueByIndex ¶
GetValueByIndex get the value by index of key order.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Map[K, V]) Keys ¶
func (m *Map[K, V]) Keys() []K
Keys returns a copy of all keys of the map, in current order.
Performance: O(n) operation. If you want iterate over the map, maybe Map.Len + Map.GetKeyByIndex is a better choice.
func (Map[K, V]) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface.
You should not call this directly, use json.Marshal instead.
func (*Map[K, V]) Pairs ¶
Pairs gives you all data the map stored as a list of pair, in current order.
Performance: O(n) operation. If you want iterate over the map, maybe Map.Len + Map.GetByIndex is a better choice.
func (*Map[K, V]) Set ¶
func (m *Map[K, V]) Set(key K, value V)
Set a value by key without change its order, or place it at end if key is not exist.
This operation is the same as Map.Add when duplicate key strategy is UpdateValueKeepOrder.
func (*Map[K, V]) SetDuplicatedKeyStrategy ¶
func (m *Map[K, V]) SetDuplicatedKeyStrategy(strategy DuplicatedKeyStrategy)
SetDuplicatedKeyStrategy set strategy when Map.Add with a duplicated key.
See document of DuplicatedKeyStrategy and its enum value for detail.
func (*Map[K, V]) Sort ¶
func (m *Map[K, V]) Sort(lessFunc PairLessFunc[K, V])
Sort will reorder the map using the given less function.
func (*Map[K, V]) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler interface.
You shouldn't call this directly, use json.Unmarshal/JSONUnmarshal instead.
func (*Map[K, V]) Values ¶
func (m *Map[K, V]) Values() []V
Values returns a copy of all values of the map, in current order.
Performance: O(n) operation. If you want iterate over the map, maybe Map.Len + Map.GetValueByIndex is a better choice.
type Object ¶
Object is a Map, whose type parameters are specialized as [string, any], used to represent dynamic objects in JSON.
type ObjectItems ¶
ObjectItems is Pairs whose type parameters are specialized as [string, any], used to represent dynamic objects in JSON.
type Pair ¶
type Pair[K, V any] struct { Key K `json:"key"` Value V `json:"value"` }
Pair is a k v pair.
func CreatePair ¶
CreatePair creates a pair from key and value.
type PairFilterFunc ¶
PairFilterFunc is the predicate for filter a pair list.
type PairLessFunc ¶
PairLessFunc is the less func to sort a pair list.
type Pairs ¶
type Pairs[K comparable, V any] struct { List []Pair[K, V] }
Pairs is a wrapper type of []Pair[K, V].
In JSON unmarshal, it will use the order of appearance in input JSON data, and marshal output will use the same order. But differ from Map, it saves all items when their key is duplicated.
When unmarshal from JSON into a ObjectItems, all JSON object will be stored in ObjectItems, all JSON array will be stored in Array, instead of normal map[string]any and []any from std lib.
Notice: Although this type behaves like a Map, because it is only a slice internally, the performance of some APIs are not very good. It is best to keep this in mind when using it.
Example ¶
package main import ( "fmt" "github.com/7sDream/geko" ) func main() { m := geko.NewPairs[string, int]() m.Add("one", 1) m.Add("three", 2) m.Add("two", 2) m.Add("three", 3) for i, length := 0, m.Len(); i < length; i++ { pair := m.GetByIndex(i) fmt.Printf("%s: %d\n", pair.Key, pair.Value) } fmt.Println("-----") m.Dedup(geko.Ignore) for i, length := 0, m.Len(); i < length; i++ { pair := m.GetByIndex(i) fmt.Printf("%s: %d\n", pair.Key, pair.Value) } }
Output: one: 1 three: 2 two: 2 three: 3 ----- one: 1 three: 2 two: 2
func NewPairs ¶
func NewPairs[K comparable, V any]() *Pairs[K, V]
NewPairs creates a new empty list.
func NewPairsFrom ¶
func NewPairsFrom[K comparable, V any](list []Pair[K, V]) *Pairs[K, V]
NewPairsFrom create a List from a slice.
func NewPairsWithCapacity ¶
func NewPairsWithCapacity[K comparable, V any](capacity int) *Pairs[K, V]
NewPairsWithCapacity likes NewPairs, but init the inner container with a capacity to optimize memory allocate.
func (*Pairs[K, V]) Add ¶
func (ps *Pairs[K, V]) Add(key K, value V)
Add a key value pair to the end of list.
func (*Pairs[K, V]) Dedup ¶
func (ps *Pairs[K, V]) Dedup(strategy DuplicatedKeyStrategy)
Dedup deduplicates this list by key.
Implemented as converting it to a Map and back.
func (*Pairs[K, V]) Delete ¶
func (ps *Pairs[K, V]) Delete(key K)
Delete all item whose key is same as provided.
Performance: O(n)
func (*Pairs[K, V]) Filter ¶
func (ps *Pairs[K, V]) Filter(pred PairFilterFunc[K, V])
Filter remove all item which make pred func return false.
Performance: O(n). More efficient then Pairs.GetByIndex + Pairs.DeleteByIndex in a loop, which is O(n^2).
func (*Pairs[K, V]) Get ¶
func (ps *Pairs[K, V]) Get(key K) []V
Get values by key.
Performance: O(n)
func (*Pairs[K, V]) GetByIndex ¶
GetByIndex get key value pair at index.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Pairs[K, V]) GetFirstOrZeroValue ¶
func (ps *Pairs[K, V]) GetFirstOrZeroValue(key K) (value V)
GetFirstOrZeroValue get first value by key, return a zero value of type V if key doesn't exist in list.
Performance: O(n)
func (*Pairs[K, V]) GetKeyByIndex ¶
GetKeyByIndex get key at index.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Pairs[K, V]) GetLastOrZeroValue ¶
func (ps *Pairs[K, V]) GetLastOrZeroValue(key K) (value V)
GetLastOrZeroValue get last value by key, return a zero value of type V if key doesn't exist in list.
Performance: O(n)
func (*Pairs[K, V]) GetValueByIndex ¶
GetValueByIndex get value at index.
You should make sure 0 <= i < Len(), panic if out of bound.
func (*Pairs[K, V]) Keys ¶
func (ps *Pairs[K, V]) Keys() []K
Keys returns all keys of the list.
Performance: O(n).
func (Pairs[K, V]) MarshalJSON ¶
MarshalJSON implements json.Marshaler interface. You should not call this directly, use json.Marshal(m) instead.
func (*Pairs[K, V]) SetByIndex ¶
SetByIndex key and value at index.
func (*Pairs[K, V]) SetKeyByIndex ¶
SetKeyByIndex changes key of item at index.
func (*Pairs[K, V]) SetValueByIndex ¶
SetValueByIndex changes value of item at index.
func (*Pairs[K, V]) Sort ¶
func (ps *Pairs[K, V]) Sort(lessFunc PairLessFunc[K, V])
Sort will reorder the list using the given less function.
func (*Pairs[K, V]) ToMap ¶
func (ps *Pairs[K, V]) ToMap(strategy DuplicatedKeyStrategy) *Map[K, V]
ToMap convert this list into a Map, with provided DuplicatedKeyStrategy.
func (*Pairs[K, V]) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler interface. You shouldn't call this directly, use json.Unmarshal(m) instead.