gg

module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2025 License: Apache-2.0

README

gg: Go Generics

GoDoc Go Report Card Go Coverage License

English | 简体中文

🔥bytedance/gg is a basic library of generics for Go language developed by ByteDance. It is based on the Go 1.18+ generic features and provides efficient, type-safe and rich generic data structures and tool functions.

Why this name?

Take the first letter of Go Generics, short and simple.

Why choose gg?

  • Stable and reliable: It is a necessary tool library for ByteDance R&D team, and it has 1w+ repository references inside.
  • Easy to use: With the design principle of simplicity and self-consistent, subcontracted according to functions, modular, semantic intuitive and unified, and low learning cost.
  • High Performance: Provides high-performance concurrent data structures, with performance 10+ times faster than standard library.
  • No three-party dependencies: Generic libraries will not introduce any three-party dependencies.
  • Version control: Follow the SemVer, guaranteeing backward compatibility.

🚀 Install

go get github.com/bytedance/gg

🔎 Table of contents

  • Generic Functional Programming
    • goption:Option type, simplifying the processing of (T, bool)
    • gresult:Result type, simplifying the processing of (T, error)
  • Generic Data Processing
    • gcond:Conditional operation
    • gvalue:Processing value T
    • gptr:Processing pointer *T
    • gslice:Processing slice []T
    • gmap:Processing map map[K]V
    • gfunc:Processing function func
    • gconv:Data type conversion
    • gson:Processing JSON
  • Generic Standard Wrapper
  • Generic Data Structures
    • tuple:Implementation of tuple provides definition of generic n-ary tuples
    • set:Implementation of set based on map[T]struct{}
    • list:Implementation of doubly linked list
    • skipset:High-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in sync.Map below Go 1.24
    • skipmap:High-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in sync.Map below Go 1.24

✨ Generic Functional Programming

goption

Option type, simplifying the processing of (T, bool)

Usage:

import (
    "github.com/bytedance/gg/goption"
)

Example:

goption.Of(1, true).Value()
// 1
goption.Nil[int]().IsNil()
// true
goption.Nil[int]().ValueOr(10)
// 10
goption.OK(1).IsOK()
// true
goption.OK(1).ValueOrZero()
// 1
goption.OfPtr((*int)(nil)).Ptr()
// nil
goption.Map(goption.OK(1), strconv.Itoa).Get()
// "1" true
gresult

Result type, simplifying the processing of (T, error)

Usage:

import (
    "github.com/bytedance/gg/gresult"
)

Example:

gresult.Of(strconv.Atoi("1")).Value()
// 1
gresult.Err[int](io.EOF).IsErr()
// true
gresult.Err[int](io.EOF).ValueOr(10)
// 10
gresult.OK(1).IsOK()
// true
gresult.OK(1).ValueOrZero()
// 1
gresult.Of(strconv.Atoi("x")).Option().Get()
// 0 false
gresult.Map(gresult.OK(1), strconv.Itoa).Get()
// "1" nil

✨ Generic Data Processing

gcond:

Conditional operation

Usage:

import (
    "github.com/bytedance/gg/gcond"
)

Example:

gcond.If(true, 1, 2)
// 1
var a *struct{ A int }
getA := func() int { return a.A }
get1 := func() int { return 1 }
gcond.IfLazy(a != nil, getA, get1)
// 1
gcond.IfLazyL(a != nil, getA, 1)
// 1
gcond.IfLazyR(a == nil, 1, getA)
// 1

gcond.Switch[string](3).
    Case(1, "1").
    CaseLazy(2, func() string { return "3" }).
    When(3, 4).Then("3/4").
    When(5, 6).ThenLazy(func() string { return "5/6" }).
    Default("other")
// 3/4
gvalue

Processing value T

Usage:

import (
    "github.com/bytedance/gg/gvalue"
)

Example1:Zero Value

a := gvalue.Zero[int]()
// 0
gvalue.IsZero(a)
// true
b := gvalue.Zero[*int]()
// nil
gvalue.IsNil(b)
// true
gvalue.Or(0, 1, 2)
// 1

Example2:Math Operation

gvalue.Max(1, 2, 3)
// 3
gvalue.Min(1, 2, 3)
// 1
gvalue.MinMax(1, 2, 3)
// 1 3
gvalue.Clamp(5, 1, 10)
// 5
gvalue.Add(1, 2)
// 3

Example3:Comparison

gvalue.Equal(1, 1)
// true
gvalue.Between(2, 1, 3)
// true

Example4:Type Assertion

gvalue.TypeAssert[int](any(1))
// 1
gvalue.TryAssert[int](any(1))
// 1 true
gptr

Processing pointer *T

Usage:

import (
    "github.com/bytedance/gg/gptr"
)

Example:

a := Of(1)
gptr.Indirect(a)
// 1

b := OfNotZero(1)
gptr.IsNotNil(b)
// true
gptr.IndirectOr(b, 2)
// 1
gptr.Indirect(gptr.Map(b, strconv.Itoa))
// "1"

c := OfNotZero(0)
// nil
gptr.IsNil(c)
// true
gptr.IndirectOr(c, 2)
// 2
gslice

Processing slice []T

Usage:

import (
    "github.com/bytedance/gg/gslice"
)

Example1:High-order Function

gslice.Map([]int{1, 2, 3, 4, 5}, strconv.Itoa)
// ["1", "2", "3", "4", "5"]
isEven := func(i int) bool { return i%2 == 0 }
gslice.Filter([]int{1, 2, 3, 4, 5}, isEven)
// [2, 4]
gslice.Reduce([]int{1, 2, 3, 4, 5}, gvalue.Add[int].Value())
// 15
gslice.Any([]int{1, 2, 3, 4, 5}, isEven)
// true
gslice.All([]int{1, 2, 3, 4, 5}, isEven)
// false

Example2:CURD Operation

gslice.Contains([]int{1, 2, 3, 4, 5}, 2)
// true
gslice.ContainsAny([]int{1, 2, 3, 4, 5}, 2, 6)
// true
gslice.ContainsAll([]int{1, 2, 3, 4, 5}, 2, 6)
// false
gslice.Index([]int{1, 2, 3, 4, 5}, 3.Value())
// 2
gslice.Find([]int{1, 2, 3, 4, 5}, isEven).Value()
// 2
gslice.First([]int{1, 2, 3, 4, 5}).Value()
// 1
gslice.Get([]int{1, 2, 3, 4, 5}, 1).Value()
// 2
gslice.Get([]int{1, 2, 3, 4, 5}, -1).Value() // Access element with negative index
// 5

Example3:Partion Operation

gslice.Range(1, 5)
// [1, 2, 3, 4]
gslice.RangeWithStep(5, 1, -2)
// [5, 3]
gslice.Take([]int{1, 2, 3, 4, 5}, 2)
// [1, 2]
gslice.Take([]int{1, 2, 3, 4, 5}, -2)
// [4, 5]
gslice.Slice([]int{1, 2, 3, 4, 5}, 1, 3)
// [2, 3]
gslice.Chunk([]int{1, 2, 3, 4, 5}, 2)
// [[1, 2], [3, 4], [5]]
gslice.Divide([]int{1, 2, 3, 4, 5}, 2)
// [[1, 2, 3], [4, 5]]
gslice.Concat([]int{1, 2}, []int{3, 4, 5})
// [1, 2, 3, 4, 5]
gslice.Flatten([][]int{{1, 2}, {3, 4, 5}})
// [1, 2, 3, 4, 5]
gslice.Partition([]int{1, 2, 3, 4, 5}, isEven)
// [2, 4], [1, 3, 5]

Example4:Math Operation

gslice.Max([]int{1, 2, 3, 4, 5}).Value()
// 5
gslice.Min([]int{1, 2, 3, 4, 5}).Value()
// 1
gslice.MinMax([]int{1, 2, 3, 4, 5}).Value().Values()
// 1 5
gslice.Sum([]int{1, 2, 3, 4, 5})
// 15

Example5:Convert to map

ToMap([]int{1, 2, 3, 4, 5}, func(i int) (string, int) { return strconv.Itoa(i), i })
// {"1":1, "2":2, "3":3, "4":4, "5":5}
ToMapValues([]int{1, 2, 3, 4, 5}, strconv.Itoa)
// {"1":1, "2":2, "3":3, "4":4, "5":5}
GroupBy([]int{1, 2, 3, 4, 5}, func(i int) string {
  if i%2 == 0 {
    return "even"
  } else {
    return "odd"
  }
})
// {"even":[2,4], "odd":[1,3,5]}

Example6:Set Operation

gslice.Union([]int{1, 2, 3}, []int{3, 4, 5})
// [1, 2, 3, 4, 5]
gslice.Intersect([]int{1, 2, 3}, []int{3, 4, 5})
// [3]
gslice.Diff([]int{1, 2, 3}, []int{3, 4, 5})
// [1, 2]
gslice.Uniq([]int{1, 1, 2, 2, 3})
// [1, 2, 3]
gslice.Dup([]int{1, 1, 2, 2, 3})
// [1, 2]

Example7:Re-order Operation

s1 := []int{5, 1, 2, 3, 4}
s2, s3, s4 := Clone(s1), Clone(s1), Clone(s1)
Sort(s1)
// [1, 2, 3, 4, 5]
SortBy(s2, func(i, j int) bool { return i > j })
// [5, 4, 3, 2, 1]
StableSortBy(s3, func(i, j int) bool { return i > j })
// [5, 4, 3, 2, 1]
Reverse(s4)
// [4, 3, 2, 1, 5]
gmap

Processing map map[K]V

Usage:

import (
    "github.com/bytedance/gg/gmap"
)

Example1:Keys / Values Getter

gmap.Keys(map[int]int{1: 2})
// [1]
gmap.Values(map[int]int{1: 2})
// [2]
gmap.Items(map[int]int{1: 2}).Unzip()
// [1] [2]
gmap.OrderedKeys(map[int]int{1: 2, 2: 3, 3: 4})
// [1, 2, 3]
gmap.OrderedValues(map[int]int{1: 2, 2: 3, 3: 4})
// [2, 3, 4]
gmap.OrderedItems(map[int]int{1: 2, 2: 3, 3: 4}).Unzip()
// [1, 2, 3] [2, 3, 4]
f := func(k, v int) string { return strconv.Itoa(k) + ":" + strconv.Itoa(v) }
gmap.ToSlice(map[int]int{1: 2}, f)
// ["1:2"]
gmap.ToOrderedSlice(map[int]int{1: 2, 2: 3, 3: 4}, f)
// ["1:2", "2:3", "3:4"]

Example2:High-order Function

gmap.Map(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) (string, string) {
    return strconv.Itoa(k), strconv.Itoa(k + 1)
})
// {"1":"2", "2":"3", "3":"4"}
gmap.Filter(map[int]int{1: 2, 2: 3, 3: 4}, func(k int, v int) bool {
    return k+v > 3
})
// {"2":2, "3":3}

Example3:CURD Operation

gmap.Contains(map[int]int{1: 2, 2: 3, 3: 4}, 1)
// true
gmap.ContainsAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)
// true
gmap.ContainsAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)
// false
gmap.Load(map[int]int{1: 2, 2: 3, 3: 4}, 1).Value()
// 2
gmap.LoadAny(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4).Value()
// 2
gmap.LoadAll(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)
// []
gmap.LoadSome(map[int]int{1: 2, 2: 3, 3: 4}, 1, 4)
// [2]

Example4:Partion Operation

Chunk(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2)
// possible result: [{1:2, 2:3}, {3:4, 4:5}, {5:6}]
Divide(map[int]int{1: 2, 2: 3, 3: 4, 4: 5, 5: 6}, 2)
// possible result: [{1:2, 2:3, 3:4}, {4:5, 5:6}]

Example5:Math Operation

gmap.Max(map[int]int{1: 2, 2: 3, 3: 4}).Value()
// 4
gmap.Min(map[int]int{1: 2, 2: 3, 3: 4}).Value()
// 2
gmap.MinMax(map[int]int{1: 2, 2: 3, 3: 4}).Value().Values()
// 2 4
gmap.Sum(map[int]int{1: 2, 2: 3, 3: 4})
// 9

Example6:Set Operation

gmap.Union(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})
// {1:2, 2:3, 3:14, 4:15, 5:16}
gmap.Intersect(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})
// {3:14}
gmap.Diff(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16})
// {1:2, 2:3}
gmap.UnionBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]())
// {1:2, 2:3, 3:4, 4:15, 5:16}
gmap.IntersectBy(gslice.Of(map[int]int{1: 2, 2: 3, 3: 4}, map[int]int{3: 14, 4: 15, 5: 16}), DiscardNew[int, int]())
// {3:4}
gfunc

Processing function func

Usage:

import (
    "github.com/bytedance/gg/gfunc"
)

Example1:Partial Application

add := Partial2(gvalue.Add[int]) // convert the Add function into a partial function
add1 := add.Partial(1)           // Bind (i.e., "freeze") the first argument to 1
add1(0)                          // 0 + 1 = 1
// 1
add1(1)                          // Reuse the partially applied function: 1 + 1 = 2
// 2
add1n2 := add1.PartialR(2)       // Bind the remaining (rightmost) argument to 2; all arguments are now fixed
add1n2()                         // 1 + 2 = 3
gconv

Data type conversion

Usage:

import (
    "github.com/bytedance/gg/gconv"
)

Example:

gconv.To[string](1)
// "1"
gconv.To[int]("1")
// 1
gconv.To[int]("x")
// 0
gconv.To[bool]("true")
// true
gconv.To[bool]("x")
// false
gconv.To[int](gptr.Of(gptr.Of(gptr.Of("1"))))
// 1
type myInt int
type myString string
gconv.To[myInt](myString("1"))
// 1
gconv.To[myString](myInt(1))
// "1"

gconv.ToE[int]("x")
// 0 strconv.ParseInt: parsing "x": invalid syntax
gson

Processing JSON

Usage:

import (
    "github.com/bytedance/gg/gson"
)

Example:

type testStruct struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}
testcase := testStruct{Name: "test", Age: 10}

gson.Marshal(testcase)
// []byte(`{"name":"test","age":10}`) nil
gson.MarshalString(testcase)
// `{"name":"test","age":10}` nil
gson.ToString(testcase)
// `{"name":"test","age":10}`
gson.MarshalIndent(testcase, "", "  ")
// "{\n  \"name\": \"test\",\n  \"age\": 10\n}" nil
gson.ToStringIndent(testcase, "", "  ")
// "{\n  \"name\": \"test\",\n  \"age\": 10\n}"
gson.Valid(`{"name":"test","age":10}`)
// true
gson.Unmarshal[testStruct](`{"name":"test","age":10}`)
// {test 10} nil

// Use high-performance JSON codecs such as Sonic or json-iterator, instead of the standard library's encoding/json.
import "github.com/bytedance/sonic"

gson.MarshalBy(sonic.ConfigDefault, testcase)
// []byte(`{"name":"test","age":10}`) nil
gson.MarshalString(sonic.ConfigDefault, testcase)
// {"name":"test","age":10}`, nil
gson.UnmarshalBy[testStruct](sonic.ConfigDefault, `{"name":"test","age":10}`)
// testStruct{Name: "test", Age: 10}, nil

// Example using Json-Iterator:
import jsoniter "github.com/json-iterator/go"

gson.MarshalBy(jsoniter.ConfigDefault, testcase)
// []byte(`{"name":"test","age":10}`) nil
gson.MarshalString(jsoniter.ConfigDefault, testcase)   
// {"name":"test","age":10}`, nil
gson.UnmarshalBy[testStruct](jsoniter.ConfigDefault, `{"name":"test","age":10}`)
// testStruct{Name: "test", Age: 10}, nil

✨ Generic Standard Wrapper

gsync

Wrap sync

Usage:

import (
    "github.com/bytedance/gg/gstd/gsync"
)

Example1:gsync.Map wraps sync.Map

sm := gsync.Map[string, int]{}
sm.Store("k", 1)
sm.Load("k")
// 1 true
sm.LoadO("k").Value()
// 1
sm.Store("k", 2)
sm.Load("k")
// 2 true
sm.LoadAndDelete("k")
// 2 true
sm.Load("k")
// 0 false
sm.LoadOrStore("k", 3)
// 3 false
sm.Load("k")
// 3 true
sm.ToMap()
// {"k":3}

Example2:gsync.Pool wraps sync.Pool

pool := Pool[*int]{
    New: func() *int {
        i := 1
        return &i
    },
}
a := pool.Get()
*a
// 1
*a = 2
pool.Put(a)
*pool.Get()
// possible result: 1 or 2

Example3:gsync.OnceXXX wraps sync.Once

onceFunc := gsync.OnceFunc(func() { fmt.Println("OnceFunc") })
onceFunc()
// "OnceFunc"
onceFunc()
// (no output)
onceFunc()
// (no output)

i := 1
onceValue := gsync.OnceValue(func() int { i++; return i })
onceValue()
// 2
onceValue()
// 2

onceValues := gsync.OnceValues(func() (int, error) { i++; return i, nil })
onceValues()
// 3 nil
onceValues()
// 3 nil

✨ Generic Data Structures

tuple

Implementation of tuple provides definition of generic n-ary tuples

Usage

import (
    "github.com/bytedance/gg/collection/tuple"
)

Example:

addr := Make2("localhost", 8080)
fmt.Printf("%s:%d\n", addr.First, addr.Second)
// localhost:8080

s := Zip2([]string{"red", "green", "blue"}, []int{14, 15, 16})
for _, v := range s {
    fmt.Printf("%s:%d\n", v.First, v.Second)
}
// red:14
// green:15
// blue:16

s.Unzip()
// ["red", "green", "blue"] [14, 15, 16]
set

Implementation of set based on map[T]struct{}

Usage

import (
    "github.com/bytedance/gg/collection/set"
)

Example:

s := New(10, 10, 12, 15)
s.Len()
// 3
s.Add(10)
// false
s.Add(11)
// true
s.Remove(11) && s.Remove(12)
// true

s.ContainsAny(10, 15)
// true
s.ContainsAny(11, 12)
// false
s.ContainsAny()
// false
s.ContainsAll(10, 15)
// true
s.ContainsAll(10, 11)
// false
s.ContainsAll()
// true

len(s.ToSlice())
// 2
list

Implementation of doubly linked list

Usage

import (
    "github.com/bytedance/gg/collection/list"
)

Example:

l := New[int]()
e1 := l.PushFront(1)        // 1
e2 := l.PushBack(2)         // 1->2
e3 := l.InsertBefore(3, e2) // 1->3->2
e4 := l.InsertAfter(4, e1)  // 1->4->3->2

l.MoveToFront(e4)    // 4->1->3->2
l.MoveToBack(e1)     // 4->3->2->1
l.MoveAfter(e3, e2)  // 4->2->3->1
l.MoveBefore(e4, e1) // 2->3->4->1

l.Len()
// 4
l.Front().Value
// 2
l.Back().Value
// 1

for e := l.Front(); e != nil; e = e.Next() {
    fmt.Println(e.Value) // 2 3 4 1
}
skipset

High-performance, scalable, concurrent-safe set based on skip-list, up to 15x faster than the built-in sync.Map below Go 1.24

⚠️ NOTICE: Go 1.24 or later, please consider using the std sync.Map, which has better performance compared to skipset in about 90% of use cases.

Usage

import (
    "github.com/bytedance/gg/collection/skipset"
)

Example:

s := skipset.New[int]()
s.Add(10)
// true
s.Add(10)
// false
s.Add(11)
// true
s.Add(12)
// true
s.Len()
// 3

s.Contains(10)
// true
s.Remove(10)
// true
s.Contains(10)
// false

s.ToSlice()
// [11, 12]

var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
    i := i
    go func() {
        defer wg.Done()
        s.Add(i)
    }()
}
wg.Wait()
s.Len()
// 1000
skipmap

High-performance, scalable, concurrent-safe map based on skip-list, up to 10x faster than the built-in sync.Map below Go 1.24

⚠️ Go 1.24 or later, please consider using the std sync.Map, which has better performance compared to skipmap in about 90% of use cases.

Usage

import (
    "github.com/bytedance/gg/collection/skipmap"
)

Example:

s := New[string, int]()
s.Store("a", 0)
s.Store("a", 1)
s.Store("b", 2)
s.Store("c", 3)
s.Len()
// 3

s.Load("a")
// 1 true
s.LoadAndDelete("a")
// 1 true
s.LoadOrStore("a", 11)
// 11 false

gson.ToString(s.ToMap())
// {"a":11, "b":2, "c": 3}

s.Delete("a")
s.Delete("b")
s.Delete("c")
var wg sync.WaitGroup
wg.Add(1000)
for i := 0; i < 1000; i++ {
    i := i
    go func() {
        defer wg.Done()
        s.Store(strconv.Itoa(i), i)
    }()
}
wg.Wait()
s.Len()
// 1000

License

gg is licensed under the Apache-2.0 license. See LICENSE for details.

2025 © Bytedance

Directories

Path Synopsis
Package collection provides implementations of generics data structures.
Package collection provides implementations of generics data structures.
list
Package list implements a doubly linked list.
Package list implements a doubly linked list.
set
Package set provides a collection that contains no duplicate elements for comparable type.
Package set provides a collection that contains no duplicate elements for comparable type.
skipmap
Package skipmap is a high-performance, scalable, concurrent-safe map based on skip-list.
Package skipmap is a high-performance, scalable, concurrent-safe map based on skip-list.
skipset
Package skipset is a high-performance, scalable, concurrent-safe set based on skip-list.
Package skipset is a high-performance, scalable, concurrent-safe set based on skip-list.
tuple
Package tuple provides definition of generic n-ary tuples, from T2 to T10.
Package tuple provides definition of generic n-ary tuples, from T2 to T10.
Package gcond helps users choose values according to various conditions in one line.
Package gcond helps users choose values according to various conditions in one line.
Package gconv helps users convert any type to the convertible type.
Package gconv helps users convert any type to the convertible type.
Package gfunc provide operations of functions.
Package gfunc provide operations of functions.
Package gmap provides generic operations for maps.
Package gmap provides generic operations for maps.
Package goption provides a generic representation of optional value.
Package goption provides a generic representation of optional value.
Package gptr provides generic operations for pointers.
Package gptr provides generic operations for pointers.
Package gresult provides a generic union type for value or error.
Package gresult provides a generic union type for value or error.
Package gslice provides generic operations for slices.
Package gslice provides generic operations for slices.
Package gson provides operations of JSON encoding and decoding.
Package gson provides operations of JSON encoding and decoding.
gstd
gsync
Package gsync provides generics wrappers of sync package.
Package gsync provides generics wrappers of sync package.
Package gvalue provides generic operations for go values.
Package gvalue provides generic operations for go values.
internal
assert
Package assert provides human-readable assertion for automated testing.
Package assert provides human-readable assertion for automated testing.
constraints
Package constraints defines a set of useful constraints to be used with type parameters.
Package constraints defines a set of useful constraints to be used with type parameters.
fastrand
Package fastrand is the fastest pseudorandom number generator in Go(multiple-cores).
Package fastrand is the fastest pseudorandom number generator in Go(multiple-cores).
iter
Package iter provides definition of generic iterator Iter and high-order functions.
Package iter provides definition of generic iterator Iter and high-order functions.
rtassert
Package rtassert provides runtime assertion.
Package rtassert provides runtime assertion.
stream
Package stream provides a Stream type and its variants for stream processing.
Package stream provides a Stream type and its variants for stream processing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL