package arrow
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/apache/arrow-go/v18/arrow/internal/debug"
)
type (
NestedType interface {
DataType
Fields () []Field
NumFields () int
}
ListLikeType interface {
DataType
Elem () DataType
ElemField () Field
}
VarLenListLikeType interface {
ListLikeType
}
)
type ListType struct {
elem Field
}
func ListOfField (f Field ) *ListType {
if f .Type == nil {
panic ("arrow: nil type for list field" )
}
return &ListType {elem : f }
}
func ListOf (t DataType ) *ListType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &ListType {elem : Field {Name : "item" , Type : t , Nullable : true }}
}
func ListOfNonNullable (t DataType ) *ListType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &ListType {elem : Field {Name : "item" , Type : t , Nullable : false }}
}
func (*ListType ) ID () Type { return LIST }
func (*ListType ) Name () string { return "list" }
func (t *ListType ) String () string {
if t .elem .Nullable {
return fmt .Sprintf ("list<%s: %s, nullable>" , t .elem .Name , t .elem .Type )
}
return fmt .Sprintf ("list<%s: %s>" , t .elem .Name , t .elem .Type )
}
func (t *ListType ) Fingerprint () string {
child := t .elem .Type .Fingerprint ()
if len (child ) > 0 {
return typeFingerprint (t ) + "{" + child + "}"
}
return ""
}
func (t *ListType ) SetElemMetadata (md Metadata ) { t .elem .Metadata = md }
func (t *ListType ) SetElemNullable (n bool ) { t .elem .Nullable = n }
func (t *ListType ) Elem () DataType { return t .elem .Type }
func (t *ListType ) ElemField () Field {
return t .elem
}
func (t *ListType ) Fields () []Field { return []Field {t .ElemField ()} }
func (t *ListType ) NumFields () int { return 1 }
func (*ListType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap (), SpecFixedWidth (Int32SizeBytes )}}
}
func (*ListType ) OffsetTypeTraits () OffsetTraits { return Int32Traits }
type LargeListType struct {
ListType
}
func (LargeListType ) ID () Type { return LARGE_LIST }
func (LargeListType ) Name () string { return "large_list" }
func (t *LargeListType ) String () string {
return "large_" + t .ListType .String ()
}
func (t *LargeListType ) Fingerprint () string {
child := t .elem .Type .Fingerprint ()
if len (child ) > 0 {
return typeFingerprint (t ) + "{" + child + "}"
}
return ""
}
func (*LargeListType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap (), SpecFixedWidth (Int64SizeBytes )}}
}
func (*LargeListType ) OffsetTypeTraits () OffsetTraits { return Int64Traits }
func LargeListOfField (f Field ) *LargeListType {
if f .Type == nil {
panic ("arrow: nil type for list field" )
}
return &LargeListType {ListType {elem : f }}
}
func LargeListOf (t DataType ) *LargeListType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &LargeListType {ListType {elem : Field {Name : "item" , Type : t , Nullable : true }}}
}
func LargeListOfNonNullable (t DataType ) *LargeListType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &LargeListType {ListType {elem : Field {Name : "item" , Type : t , Nullable : false }}}
}
type FixedSizeListType struct {
n int32
elem Field
}
func FixedSizeListOfField (n int32 , f Field ) *FixedSizeListType {
if f .Type == nil {
panic ("arrow: nil DataType" )
}
if n <= 0 {
panic ("arrow: invalid size" )
}
return &FixedSizeListType {n : n , elem : f }
}
func FixedSizeListOf (n int32 , t DataType ) *FixedSizeListType {
if t == nil {
panic ("arrow: nil DataType" )
}
if n <= 0 {
panic ("arrow: invalid size" )
}
return &FixedSizeListType {n : n , elem : Field {Name : "item" , Type : t , Nullable : true }}
}
func FixedSizeListOfNonNullable (n int32 , t DataType ) *FixedSizeListType {
if t == nil {
panic ("arrow: nil DataType" )
}
if n <= 0 {
panic ("arrow: invalid size" )
}
return &FixedSizeListType {n : n , elem : Field {Name : "item" , Type : t , Nullable : false }}
}
func (*FixedSizeListType ) ID () Type { return FIXED_SIZE_LIST }
func (*FixedSizeListType ) Name () string { return "fixed_size_list" }
func (t *FixedSizeListType ) String () string {
if t .elem .Nullable {
return fmt .Sprintf ("fixed_size_list<%s: %s, nullable>[%d]" , t .elem .Name , t .elem .Type , t .n )
}
return fmt .Sprintf ("fixed_size_list<%s: %s>[%d]" , t .elem .Name , t .elem .Type , t .n )
}
func (t *FixedSizeListType ) SetElemNullable (n bool ) { t .elem .Nullable = n }
func (t *FixedSizeListType ) Elem () DataType { return t .elem .Type }
func (t *FixedSizeListType ) Len () int32 { return t .n }
func (t *FixedSizeListType ) ElemField () Field {
return t .elem
}
func (t *FixedSizeListType ) Fingerprint () string {
child := t .elem .Type .Fingerprint ()
if len (child ) > 0 {
return fmt .Sprintf ("%s[%d]{%s}" , typeFingerprint (t ), t .n , child )
}
return ""
}
func (t *FixedSizeListType ) Fields () []Field { return []Field {t .ElemField ()} }
func (t *FixedSizeListType ) NumFields () int { return 1 }
func (*FixedSizeListType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap ()}}
}
type ListViewType struct {
elem Field
}
func ListViewOfField (f Field ) *ListViewType {
if f .Type == nil {
panic ("arrow: nil DataType" )
}
return &ListViewType {elem : f }
}
func ListViewOf (t DataType ) *ListViewType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &ListViewType {elem : Field {Name : "item" , Type : t , Nullable : true }}
}
func ListViewOfNonNullable (t DataType ) *ListViewType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &ListViewType {elem : Field {Name : "item" , Type : t , Nullable : false }}
}
func (*ListViewType ) ID () Type { return LIST_VIEW }
func (*ListViewType ) Name () string { return "list_view" }
func (t *ListViewType ) String () string {
if t .elem .Nullable {
return fmt .Sprintf ("list_view<%s: %s, nullable>" , t .elem .Name , t .elem .Type )
}
return fmt .Sprintf ("list_view<%s: %s>" , t .elem .Name , t .elem .Type )
}
func (t *ListViewType ) Fingerprint () string {
child := t .elem .Type .Fingerprint ()
if len (child ) > 0 {
return typeFingerprint (t ) + "{" + child + "}"
}
return ""
}
func (t *ListViewType ) SetElemMetadata (md Metadata ) { t .elem .Metadata = md }
func (t *ListViewType ) SetElemNullable (n bool ) { t .elem .Nullable = n }
func (t *ListViewType ) Elem () DataType { return t .elem .Type }
func (t *ListViewType ) ElemField () Field {
return t .elem
}
func (t *ListViewType ) Fields () []Field { return []Field {t .ElemField ()} }
func (t *ListViewType ) NumFields () int { return 1 }
func (*ListViewType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap (), SpecFixedWidth (Int32SizeBytes ), SpecFixedWidth (Int32SizeBytes )}}
}
func (*ListViewType ) OffsetTypeTraits () OffsetTraits { return Int32Traits }
type LargeListViewType struct {
elem Field
}
func LargeListViewOfField (f Field ) *LargeListViewType {
if f .Type == nil {
panic ("arrow: nil DataType" )
}
return &LargeListViewType {elem : f }
}
func LargeListViewOf (t DataType ) *LargeListViewType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &LargeListViewType {elem : Field {Name : "item" , Type : t , Nullable : true }}
}
func LargeListViewOfNonNullable (t DataType ) *LargeListViewType {
if t == nil {
panic ("arrow: nil DataType" )
}
return &LargeListViewType {elem : Field {Name : "item" , Type : t , Nullable : false }}
}
func (*LargeListViewType ) ID () Type { return LARGE_LIST_VIEW }
func (*LargeListViewType ) Name () string { return "large_list_view" }
func (t *LargeListViewType ) String () string {
if t .elem .Nullable {
return fmt .Sprintf ("large_list_view<%s: %s, nullable>" , t .elem .Name , t .elem .Type )
}
return fmt .Sprintf ("large_list_view<%s: %s>" , t .elem .Name , t .elem .Type )
}
func (t *LargeListViewType ) Fingerprint () string {
child := t .elem .Type .Fingerprint ()
if len (child ) > 0 {
return typeFingerprint (t ) + "{" + child + "}"
}
return ""
}
func (t *LargeListViewType ) SetElemMetadata (md Metadata ) { t .elem .Metadata = md }
func (t *LargeListViewType ) SetElemNullable (n bool ) { t .elem .Nullable = n }
func (t *LargeListViewType ) Elem () DataType { return t .elem .Type }
func (t *LargeListViewType ) ElemField () Field {
return t .elem
}
func (t *LargeListViewType ) Fields () []Field { return []Field {t .ElemField ()} }
func (t *LargeListViewType ) NumFields () int { return 1 }
func (*LargeListViewType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap (), SpecFixedWidth (Int64SizeBytes ), SpecFixedWidth (Int64SizeBytes )}}
}
func (*LargeListViewType ) OffsetTypeTraits () OffsetTraits { return Int64Traits }
type StructType struct {
fields []Field
index map [string ][]int
meta Metadata
}
func StructOf (fs ...Field ) *StructType {
n := len (fs )
if n == 0 {
return &StructType {}
}
t := &StructType {
fields : make ([]Field , n ),
index : make (map [string ][]int , n ),
}
for i , f := range fs {
if f .Type == nil {
panic ("arrow: field with nil DataType" )
}
t .fields [i ] = Field {
Name : f .Name ,
Type : f .Type ,
Nullable : f .Nullable ,
Metadata : f .Metadata .clone (),
}
if indices , exists := t .index [f .Name ]; exists {
t .index [f .Name ] = append (indices , i )
} else {
t .index [f .Name ] = []int {i }
}
}
return t
}
func (*StructType ) ID () Type { return STRUCT }
func (*StructType ) Name () string { return "struct" }
func (t *StructType ) String () string {
var o strings .Builder
o .WriteString ("struct<" )
for i , f := range t .fields {
if i > 0 {
o .WriteString (", " )
}
o .WriteString (fmt .Sprintf ("%s: %v" , f .Name , f .Type ))
}
o .WriteString (">" )
return o .String ()
}
func (t *StructType ) Fields () []Field {
fields := make ([]Field , len (t .fields ))
copy (fields , t .fields )
return fields
}
func (t *StructType ) NumFields () int { return len (t .fields ) }
func (t *StructType ) Field (i int ) Field { return t .fields [i ] }
func (t *StructType ) FieldByName (name string ) (Field , bool ) {
i , ok := t .index [name ]
if !ok {
return Field {}, false
}
return t .fields [i [0 ]], true
}
func (t *StructType ) FieldIdx (name string ) (int , bool ) {
i , ok := t .index [name ]
if ok {
return i [0 ], true
}
return -1 , false
}
func (t *StructType ) FieldsByName (n string ) ([]Field , bool ) {
indices , ok := t .index [n ]
if !ok {
return nil , ok
}
fields := make ([]Field , 0 , len (indices ))
for _ , v := range indices {
fields = append (fields , t .fields [v ])
}
return fields , ok
}
func (t *StructType ) FieldIndices (name string ) []int {
return t .index [name ]
}
func (t *StructType ) Fingerprint () string {
var b strings .Builder
b .WriteString (typeFingerprint (t ))
b .WriteByte ('{' )
for _ , c := range t .fields {
child := c .Fingerprint ()
if len (child ) == 0 {
return ""
}
b .WriteString (child )
b .WriteByte (';' )
}
b .WriteByte ('}' )
return b .String ()
}
func (*StructType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecBitmap ()}}
}
type MapType struct {
value *ListType
KeysSorted bool
}
func MapOf (key , item DataType ) *MapType {
if key == nil || item == nil {
panic ("arrow: nil key or item type for MapType" )
}
return &MapType {value : ListOf (StructOf (Field {Name : "key" , Type : key }, Field {Name : "value" , Type : item , Nullable : true }))}
}
func MapOfFields (key , item Field ) *MapType {
if key .Type == nil || item .Type == nil {
panic ("arrow: nil key or item type for MapType" )
}
if key .Nullable {
panic ("arrow: key field must be non-nullable" )
}
key .Name = "key"
item .Name = "value"
return &MapType {value : ListOfField (Field {
Name : "entries" ,
Type : StructOf (key , item ),
})}
}
func MapOfWithMetadata (key DataType , keyMetadata Metadata , item DataType , itemMetadata Metadata ) *MapType {
if key == nil || item == nil {
panic ("arrow: nil key or item type for MapType" )
}
return &MapType {value : ListOf (StructOf (Field {
Name : "key" ,
Type : key ,
Metadata : keyMetadata ,
}, Field {
Name : "value" ,
Type : item ,
Nullable : true ,
Metadata : itemMetadata ,
}))}
}
func (*MapType ) ID () Type { return MAP }
func (*MapType ) Name () string { return "map" }
func (t *MapType ) String () string {
var o strings .Builder
o .WriteString (fmt .Sprintf ("map<%s, %s" ,
t .value .Elem ().(*StructType ).Field (0 ).Type ,
t .value .Elem ().(*StructType ).Field (1 ).Type ))
if t .KeysSorted {
o .WriteString (", keys_sorted" )
}
if t .ItemField ().Nullable {
o .WriteString (", items_nullable" )
} else {
o .WriteString (", items_non_nullable" )
}
o .WriteString (">" )
return o .String ()
}
func (t *MapType ) KeyField () Field { return t .value .Elem ().(*StructType ).Field (0 ) }
func (t *MapType ) KeyType () DataType { return t .KeyField ().Type }
func (t *MapType ) ItemField () Field { return t .value .Elem ().(*StructType ).Field (1 ) }
func (t *MapType ) ItemType () DataType { return t .ItemField ().Type }
func (t *MapType ) ValueType () *StructType { return t .Elem ().(*StructType ) }
func (t *MapType ) ValueField () Field { return t .ElemField () }
func (t *MapType ) Elem () DataType { return t .value .Elem () }
func (t *MapType ) ElemField () Field { return Field {Name : "entries" , Type : t .Elem ()} }
func (t *MapType ) SetItemNullable (nullable bool ) {
t .value .Elem ().(*StructType ).fields [1 ].Nullable = nullable
}
func (t *MapType ) Fingerprint () string {
keyFingerprint := t .KeyType ().Fingerprint ()
itemFingerprint := t .ItemType ().Fingerprint ()
if keyFingerprint == "" || itemFingerprint == "" {
return ""
}
fingerprint := typeFingerprint (t )
if t .KeysSorted {
fingerprint += "s"
}
return fingerprint + "{" + keyFingerprint + itemFingerprint + "}"
}
func (t *MapType ) Fields () []Field { return []Field {t .ElemField ()} }
func (t *MapType ) NumFields () int { return 1 }
func (t *MapType ) Layout () DataTypeLayout {
return t .value .Layout ()
}
func (*MapType ) OffsetTypeTraits () OffsetTraits { return Int32Traits }
type (
UnionTypeCode = int8
UnionMode int8
)
const (
MaxUnionTypeCode UnionTypeCode = 127
InvalidUnionChildID int = -1
SparseMode UnionMode = iota
DenseMode
)
type UnionType interface {
NestedType
Mode () UnionMode
ChildIDs () []int
TypeCodes () []UnionTypeCode
MaxTypeCode () UnionTypeCode
}
func UnionOf (mode UnionMode , fields []Field , typeCodes []UnionTypeCode ) UnionType {
switch mode {
case SparseMode :
return SparseUnionOf (fields , typeCodes )
case DenseMode :
return DenseUnionOf (fields , typeCodes )
default :
panic ("arrow: invalid union mode" )
}
}
type unionType struct {
children []Field
typeCodes []UnionTypeCode
childIDs [int (MaxUnionTypeCode ) + 1 ]int
}
func (t *unionType ) init (fields []Field , typeCodes []UnionTypeCode ) {
t .childIDs [0 ] = InvalidUnionChildID
for i := 1 ; i < len (t .childIDs ); i *= 2 {
copy (t .childIDs [i :], t .childIDs [:i ])
}
t .children = fields
t .typeCodes = typeCodes
for i , tc := range t .typeCodes {
t .childIDs [tc ] = i
}
}
func (t *unionType ) Fields () []Field {
fields := make ([]Field , len (t .children ))
copy (fields , t .children )
return fields
}
func (t *unionType ) NumFields () int { return len (t .children ) }
func (t *unionType ) TypeCodes () []UnionTypeCode { return t .typeCodes }
func (t *unionType ) ChildIDs () []int { return t .childIDs [:] }
func (t *unionType ) validate (fields []Field , typeCodes []UnionTypeCode , _ UnionMode ) error {
if len (fields ) != len (typeCodes ) {
return errors .New ("arrow: union types should have the same number of fields as type codes" )
}
for _ , c := range typeCodes {
if c < 0 || c > MaxUnionTypeCode {
return errors .New ("arrow: union type code out of bounds" )
}
}
return nil
}
func (t *unionType ) MaxTypeCode () (max UnionTypeCode ) {
if len (t .typeCodes ) == 0 {
return
}
max = t .typeCodes [0 ]
for _ , c := range t .typeCodes [1 :] {
if c > max {
max = c
}
}
return
}
func (t *unionType ) String () string {
var b strings .Builder
b .WriteByte ('<' )
for i := range t .typeCodes {
if i != 0 {
b .WriteString (", " )
}
fmt .Fprintf (&b , "%s=%d" , t .children [i ], t .typeCodes [i ])
}
b .WriteByte ('>' )
return b .String ()
}
func (t *unionType ) fingerprint () string {
var b strings .Builder
for _ , c := range t .typeCodes {
fmt .Fprintf (&b , ":%d" , c )
}
b .WriteString ("]{" )
for _ , c := range t .children {
fingerprint := c .Fingerprint ()
if len (fingerprint ) == 0 {
return ""
}
b .WriteString (fingerprint )
b .WriteByte (';' )
}
b .WriteByte ('}' )
return b .String ()
}
func fieldsFromArrays(arrays []Array , names ...string ) (ret []Field ) {
ret = make ([]Field , len (arrays ))
if len (names ) == 0 {
for i , c := range arrays {
ret [i ] = Field {Name : strconv .Itoa (i ), Type : c .DataType (), Nullable : true }
}
} else {
debug .Assert (len (names ) == len (arrays ), "mismatch of arrays and names" )
for i , c := range arrays {
ret [i ] = Field {Name : names [i ], Type : c .DataType (), Nullable : true }
}
}
return
}
type SparseUnionType struct {
unionType
}
func SparseUnionFromArrays (children []Array , fields []string , codes []UnionTypeCode ) *SparseUnionType {
if len (codes ) == 0 {
codes = make ([]UnionTypeCode , len (children ))
for i := range children {
codes [i ] = UnionTypeCode (i )
}
}
return SparseUnionOf (fieldsFromArrays (children , fields ...), codes )
}
func SparseUnionOf (fields []Field , typeCodes []UnionTypeCode ) *SparseUnionType {
ret := &SparseUnionType {}
if err := ret .validate (fields , typeCodes , ret .Mode ()); err != nil {
panic (err )
}
ret .init (fields , typeCodes )
return ret
}
func (SparseUnionType ) ID () Type { return SPARSE_UNION }
func (SparseUnionType ) Name () string { return "sparse_union" }
func (SparseUnionType ) Mode () UnionMode { return SparseMode }
func (t *SparseUnionType ) Fingerprint () string {
return typeFingerprint (t ) + "[s" + t .fingerprint ()
}
func (SparseUnionType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecFixedWidth (Uint8SizeBytes )}}
}
func (t *SparseUnionType ) String () string {
return t .Name () + t .unionType .String ()
}
type DenseUnionType struct {
unionType
}
func DenseUnionFromArrays (children []Array , fields []string , codes []UnionTypeCode ) *DenseUnionType {
if len (codes ) == 0 {
codes = make ([]UnionTypeCode , len (children ))
for i := range children {
codes [i ] = UnionTypeCode (i )
}
}
return DenseUnionOf (fieldsFromArrays (children , fields ...), codes )
}
func DenseUnionOf (fields []Field , typeCodes []UnionTypeCode ) *DenseUnionType {
ret := &DenseUnionType {}
if err := ret .validate (fields , typeCodes , ret .Mode ()); err != nil {
panic (err )
}
ret .init (fields , typeCodes )
return ret
}
func (DenseUnionType ) ID () Type { return DENSE_UNION }
func (DenseUnionType ) Name () string { return "dense_union" }
func (DenseUnionType ) Mode () UnionMode { return DenseMode }
func (t *DenseUnionType ) Fingerprint () string {
return typeFingerprint (t ) + "[s" + t .fingerprint ()
}
func (DenseUnionType ) Layout () DataTypeLayout {
return DataTypeLayout {Buffers : []BufferSpec {SpecFixedWidth (Uint8SizeBytes ), SpecFixedWidth (Int32SizeBytes )}}
}
func (DenseUnionType ) OffsetTypeTraits () OffsetTraits { return Int32Traits }
func (t *DenseUnionType ) String () string {
return t .Name () + t .unionType .String ()
}
type Field struct {
Name string
Type DataType
Nullable bool
Metadata Metadata
}
func (f Field ) Fingerprint () string {
typeFingerprint := f .Type .Fingerprint ()
if typeFingerprint == "" {
return ""
}
var b strings .Builder
b .WriteByte ('F' )
if f .Nullable {
b .WriteByte ('n' )
} else {
b .WriteByte ('N' )
}
b .WriteString (f .Name )
b .WriteByte ('{' )
b .WriteString (typeFingerprint )
b .WriteByte ('}' )
return b .String ()
}
func (f Field ) HasMetadata () bool { return f .Metadata .Len () != 0 }
func (f Field ) Equal (o Field ) bool {
switch {
case f .Name != o .Name :
return false
case f .Nullable != o .Nullable :
return false
case !TypeEqual (f .Type , o .Type , CheckMetadata ()):
return false
case !f .Metadata .Equal (o .Metadata ):
return false
}
return true
}
func (f Field ) String () string {
var o strings .Builder
nullable := ""
if f .Nullable {
nullable = ", nullable"
}
fmt .Fprintf (&o , "%s: type=%v%v" , f .Name , f .Type , nullable )
if f .HasMetadata () {
fmt .Fprintf (&o , "\n%*.smetadata: %v" , len (f .Name )+2 , "" , f .Metadata )
}
return o .String ()
}
var (
_ DataType = (*ListType )(nil )
_ DataType = (*LargeListType )(nil )
_ DataType = (*FixedSizeListType )(nil )
_ DataType = (*StructType )(nil )
_ DataType = (*MapType )(nil )
_ DataType = (*DenseUnionType )(nil )
_ DataType = (*SparseUnionType )(nil )
_ NestedType = (*ListType )(nil )
_ NestedType = (*LargeListType )(nil )
_ NestedType = (*FixedSizeListType )(nil )
_ NestedType = (*MapType )(nil )
_ NestedType = (*DenseUnionType )(nil )
_ NestedType = (*SparseUnionType )(nil )
_ ListLikeType = (*ListType )(nil )
_ ListLikeType = (*LargeListType )(nil )
_ ListLikeType = (*FixedSizeListType )(nil )
_ ListLikeType = (*MapType )(nil )
_ VarLenListLikeType = (*ListType )(nil )
_ VarLenListLikeType = (*LargeListType )(nil )
_ VarLenListLikeType = (*ListViewType )(nil )
_ VarLenListLikeType = (*LargeListViewType )(nil )
_ VarLenListLikeType = (*FixedSizeListType )(nil )
_ VarLenListLikeType = (*MapType )(nil )
)
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .