Go Docs

Build Status

Codecov Status

Go Report Card

WARNING: this is an experimental package and is not intended for
production use.

Variant (also known as tagged union) allows to store values of one of the following types:

  • int,
  • float64,
  • string,
  • []byte slice,
  • ordered list of Variant,
  • ordered key/value list of Variant, where key is a string.
  • empty or no value.

Variant implementation is optimized for performance: for minimal CPU and
memory usage. The implementation currently targets amd64 or 386 GOARCH
only (it can be extended to other architectures).

This repository includes benchmarks that compare this implementation
of Variant with several other functionally equivalent implementations.


To run the benchmarks do make benchmark.

Below is a chart that shows CPU times of a few operations for
this and several alternate variant implementations (lower is better):

  • Interface – typical
    interface-based implementation of a variant
    data type (implementations like this are common in Go).

  • Struct – a struct
    that has a field for each possible value type plus
    a tag to store the type of the value.

  • Variant – this implementation.

CPU Usage

To see what each specific benchmark does prepend the label in the
x axis with “BenchmarkVariant” and find the corresponding function
in the source code (e.g. BenchmarkVariantIntGet).

The chart above shows benchmarking results for amd64 version,
compiled using go 1.15, running on Ubuntu 18 system with
Intel i7 7500U processor.


To use a Variant first create and store a value in it,
check the stored value type and read the value. For example:

import "github.com/tigrannajaryan/govariant/variant"

v := variant.NewInt(123)
if v.Type() == TypeInt {
	x := v.IntVal() // x is now int value 123.

Below is a more complete example that shows how to create a Variant,
check the type, fetch the data, iterate over list types, etc.

import (


// variantToString converts a Variant to a human readable string.
func variantToString(v variant.Variant) string {
	switch v.Type() {
	case variant.TypeEmpty:
		return ""

	case variant.TypeInt:
		return fmt.Sprintf("%v", v.IntVal())

	case variant.TypeFloat64:
		return fmt.Sprintf("%v", v.Float64Val())

	case variant.TypeString:
		return fmt.Sprintf("%q", v.StringVal())

	case variant.TypeBytes:
		return fmt.Sprintf("0x%X", v.Bytes())

	case variant.TypeValueList:
		sb := strings.Builder{}
		for i, e := range v.ValueList() {
			if i > 0 {
				sb.WriteString(", ")
		return sb.String()

	case variant.TypeKeyValueList:
		sb := strings.Builder{}
		for i, kv := range v.KeyValueList() {
			if i > 0 {
				sb.WriteString(", ")
			sb.WriteString(fmt.Sprintf("%q: ", kv.Key))
		return sb.String()
	panic("Unknown variant type")

func printVariant(v variant.Variant) {
	fmt.Printf("%sn", variantToString(v))

func Example() {
	v := variant.NewInt(123)

	v = variant.NewFloat64(1.23)

	v = variant.NewString("Hello, World!")

	v = variant.NewBytes([]byte{0xAF, 0xCD, 0x34})

	v = variant.NewValueList(

	v = variant.NewKeyValueList(
			{Key: "intval", Value: variant.NewInt(10)},
			{Key: "a string", Value: variant.NewString("abc")},
			{Key: "list", Value: v},

	// Output: 
	// 123
	// 1.23
	// "Hello, World!"
	// 0xAFCD34
	// [10, "abc"]
	// {"intval": 10, "a string": "abc", "list": [10, "abc"]}

Read More

ترك الرد

من فضلك ادخل تعليقك
من فضلك ادخل اسمك هنا