Memory efficient cross-platform serialization library with zero-copy deserialization supporting 15+ programming languages.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Go implementation of FlatBuffers leveraging Go's memory management and providing idiomatic Go interfaces for FlatBuffer operations. The Go binding maintains zero-copy deserialization benefits while integrating seamlessly with Go's type system and concurrency features.
Install FlatBuffers for Go and import the necessary components.
# Install FlatBuffers Go package
go get github.com/google/flatbuffers/go
# Or with specific version
go get github.com/google/flatbuffers/go@v25.2.10// Core imports
import (
flatbuffers "github.com/google/flatbuffers/go"
)
// Common additional imports
import (
"fmt"
"io/ioutil"
"os"
)Main builder type for constructing FlatBuffer data in Go applications.
type Builder struct {
// Internal fields (not exported)
}
/**
* Create new FlatBuffer builder
* @param initialSize Initial buffer size in bytes
* @return New Builder instance
*/
func NewBuilder(initialSize int) *Builder
/**
* Reset builder for reuse, keeping allocated memory
*/
func (b *Builder) Reset()
/**
* Get current write position/size
* @return Current offset
*/
func (b *Builder) Offset() UOffsetT
/**
* Create string and return its offset
* @param s String to store
* @return Offset to string
*/
func (b *Builder) CreateString(s string) UOffsetT
/**
* Create byte vector from slice
* @param v Byte slice to store
* @return Offset to vector
*/
func (b *Builder) CreateByteVector(v []byte) UOffsetT
/**
* Start building a vector
* @param elemSize Size of each element
* @param numElems Number of elements
* @param alignment Required alignment
*/
func (b *Builder) StartVector(elemSize, numElems, alignment int)
/**
* End vector construction
* @return Offset to completed vector
*/
func (b *Builder) EndVector() UOffsetT
/**
* Start building a table
* @param numFields Number of fields in table
*/
func (b *Builder) StartObject(numFields int)
/**
* Add slot for field (prepares vtable entry)
* @param slotnum Field slot number
*/
func (b *Builder) Slot(slotnum int)
/**
* Add byte value to current position
* @param x Byte value
*/
func (b *Builder) PrependByte(x byte)
/**
* Add uint8 value to current position
* @param x Uint8 value
*/
func (b *Builder) PrependUint8(x uint8)
/**
* Add int8 value to current position
* @param x Int8 value
*/
func (b *Builder) PrependInt8(x int8)
/**
* Add uint16 value to current position
* @param x Uint16 value
*/
func (b *Builder) PrependUint16(x uint16)
/**
* Add int16 value to current position
* @param x Int16 value
*/
func (b *Builder) PrependInt16(x int16)
/**
* Add uint32 value to current position
* @param x Uint32 value
*/
func (b *Builder) PrependUint32(x uint32)
/**
* Add int32 value to current position
* @param x Int32 value
*/
func (b *Builder) PrependInt32(x int32)
/**
* Add uint64 value to current position
* @param x Uint64 value
*/
func (b *Builder) PrependUint64(x uint64)
/**
* Add int64 value to current position
* @param x Int64 value
*/
func (b *Builder) PrependInt64(x int64)
/**
* Add float32 value to current position
* @param x Float32 value
*/
func (b *Builder) PrependFloat32(x float32)
/**
* Add float64 value to current position
* @param x Float64 value
*/
func (b *Builder) PrependFloat64(x float64)
/**
* Add offset value relative to current position
* @param off Offset value
*/
func (b *Builder) PrependUOffsetTRelative(off UOffsetT)
/**
* End table construction
* @return Offset to completed table
*/
func (b *Builder) EndObject() UOffsetT
/**
* Finish buffer with root table
* @param rootTable Offset to root table
*/
func (b *Builder) Finish(rootTable UOffsetT)
/**
* Finish buffer with root table and file identifier
* @param rootTable Offset to root table
* @param fileIdentifier 4-byte file identifier
*/
func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fileIdentifier []byte)
/**
* Finish buffer with size prefix
* @param rootTable Offset to root table
*/
func (b *Builder) FinishSizePrefixed(rootTable UOffsetT)
/**
* Get finished buffer as byte slice
* @return Byte slice containing FlatBuffer data
*/
func (b *Builder) FinishedBytes() []byte
/**
* Get buffer size
* @return Size in bytes
*/
func (b *Builder) Size() intUsage Example:
package main
import (
flatbuffers "github.com/google/flatbuffers/go"
"fmt"
)
func main() {
// Create builder
builder := flatbuffers.NewBuilder(1024)
// Create string
name := builder.CreateString("Player")
// Create vector
scores := []int32{100, 200, 300, 400, 500}
builder.StartVector(4, len(scores), 4)
for i := len(scores) - 1; i >= 0; i-- {
builder.PrependInt32(scores[i])
}
scoresOffset := builder.EndVector()
// Create table
builder.StartObject(3)
builder.PrependUOffsetTRelative(name) // name field (slot 0)
builder.Slot(0)
builder.PrependInt32(42) // level field (slot 1)
builder.Slot(1)
builder.PrependUOffsetTRelative(scoresOffset) // scores field (slot 2)
builder.Slot(2)
player := builder.EndObject()
// Finish buffer
builder.Finish(player)
// Get binary data
buffer := builder.FinishedBytes()
fmt.Printf("Buffer size: %d bytes\n", len(buffer))
}Core type definitions used throughout the FlatBuffers Go API.
// Basic offset and size types
type UOffsetT uint32 // Unsigned offset type
type SOffsetT int32 // Signed offset type
type VOffsetT uint16 // VTable offset type
// Constants
const (
SizeUOffsetT = 4 // Size of UOffsetT in bytes
SizeSOffsetT = 4 // Size of SOffsetT in bytes
SizeVOffsetT = 2 // Size of VOffsetT in bytes
FileIdentifierLength = 4 // Length of file identifier
SizePrefixLength = 4 // Size prefix length
)
// Table interface for generated table types
type Table struct {
Bytes []byte // Buffer containing table data
Pos UOffsetT // Position of table in buffer
}
/**
* Get field offset from vtable
* @param table Table instance
* @param vtableOffset Offset in vtable
* @return Field offset or 0 if not present
*/
func (t *Table) Offset(vtableOffset VOffsetT) VOffsetT
/**
* Get indirect offset (for tables, vectors, strings)
* @param table Table instance
* @param offset Field offset
* @return Indirect offset
*/
func (t *Table) Indirect(offset UOffsetT) UOffsetT
/**
* Get string at offset
* @param table Table instance
* @param offset String offset
* @return String value
*/
func (t *Table) String(offset UOffsetT) string
/**
* Get byte slice at offset
* @param table Table instance
* @param offset Offset to data
* @param length Data length
* @return Byte slice
*/
func (t *Table) ByteVector(offset UOffsetT) []byte
/**
* Get vector length at offset
* @param table Table instance
* @param offset Vector offset
* @return Vector length
*/
func (t *Table) VectorLen(offset UOffsetT) int
/**
* Get vector element position
* @param table Table instance
* @param offset Vector offset
* @param i Element index
* @param elemSize Element size in bytes
* @return Element position
*/
func (t *Table) Vector(offset UOffsetT) UOffsetTWhen using flatc --go, the compiler generates Go code following these patterns.
// Example generated Go (from monster.fbs):
package MyGame
import (
flatbuffers "github.com/google/flatbuffers/go"
)
// Vec3 struct definition
type Vec3 struct {
X float32
Y float32
Z float32
}
// Pack Vec3 into builder
func (v *Vec3) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
builder.Prep(4, 12)
builder.PrependFloat32(v.Z)
builder.PrependFloat32(v.Y)
builder.PrependFloat32(v.X)
return builder.Offset()
}
// Monster table type
type Monster struct {
_tab flatbuffers.Table
}
// Get Monster from buffer bytes at offset
func GetRootAsMonster(buf []byte, offset flatbuffers.UOffsetT) *Monster {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &Monster{}
x.Init(buf, n+offset)
return x
}
// Initialize Monster with buffer and position
func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
// Get Monster table
func (rcv *Monster) Table() *flatbuffers.Table {
return &rcv._tab
}
// Get position as Vec3
func (rcv *Monster) Pos(obj *Vec3) *Vec3 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Pos + o
if obj == nil {
obj = &Vec3{}
}
obj.X = flatbuffers.GetFloat32(rcv._tab.Bytes[x:])
obj.Y = flatbuffers.GetFloat32(rcv._tab.Bytes[x+4:])
obj.Z = flatbuffers.GetFloat32(rcv._tab.Bytes[x+8:])
return obj
}
return nil
}
// Get mana value
func (rcv *Monster) Mana() int16 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return flatbuffers.GetInt16(rcv._tab.Bytes[rcv._tab.Pos+o:])
}
return 150 // default value
}
// Get HP value
func (rcv *Monster) Hp() int16 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return flatbuffers.GetInt16(rcv._tab.Bytes[rcv._tab.Pos+o:])
}
return 100 // default value
}
// Get name string
func (rcv *Monster) Name() string {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.String(rcv._tab.Pos + o)
}
return ""
}
// Get inventory item at index
func (rcv *Monster) Inventory(j int) uint8 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
a := rcv._tab.Vector(rcv._tab.Pos + o)
return flatbuffers.GetUint8(rcv._tab.Bytes[a+flatbuffers.UOffsetT(j*1):])
}
return 0
}
// Get inventory vector length
func (rcv *Monster) InventoryLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.VectorLen(rcv._tab.Pos + o)
}
return 0
}
// Get inventory as byte slice
func (rcv *Monster) InventoryBytes() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.ByteVector(rcv._tab.Pos + o)
}
return nil
}
// Monster builder functions
func MonsterStart(builder *flatbuffers.Builder) {
builder.StartObject(6)
}
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
builder.PrependStructSlot(0, pos, 0)
}
func MonsterAddMana(builder *flatbuffers.Builder, mana int16) {
builder.PrependInt16Slot(1, mana, 150)
}
func MonsterAddHp(builder *flatbuffers.Builder, hp int16) {
builder.PrependInt16Slot(2, hp, 100)
}
func MonsterAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(3, name, 0)
}
func MonsterAddInventory(builder *flatbuffers.Builder, inventory flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(5, inventory, 0)
}
func MonsterStartInventoryVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(1, numElems, 1)
}
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
// Convenience function to create Monster
func MonsterCreate(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT, mana int16, hp int16, name flatbuffers.UOffsetT, inventory flatbuffers.UOffsetT) flatbuffers.UOffsetT {
MonsterStart(builder)
MonsterAddPos(builder, pos)
MonsterAddMana(builder, mana)
MonsterAddHp(builder, hp)
MonsterAddName(builder, name)
MonsterAddInventory(builder, inventory)
return MonsterEnd(builder)
}Utility functions for working with FlatBuffer data in Go.
// Read scalar values from byte slices
func GetUint8(buf []byte) uint8
func GetInt8(buf []byte) int8
func GetUint16(buf []byte) uint16
func GetInt16(buf []byte) int16
func GetUint32(buf []byte) uint32
func GetInt32(buf []byte) int32
func GetUint64(buf []byte) uint64
func GetInt64(buf []byte) int64
func GetFloat32(buf []byte) float32
func GetFloat64(buf []byte) float64
// Get offset values
func GetUOffsetT(buf []byte) UOffsetT
func GetSOffsetT(buf []byte) SOffsetT
func GetVOffsetT(buf []byte) VOffsetT
// Buffer validation
func SizeUint32(buf []byte) uint32 // Get size prefix
func SizePrefixedBuffer(buf []byte) []byte // Get buffer without size prefix
// String operations
func GetRootAsString(buf []byte, offset UOffsetT) stringWorking with files and Go's concurrency features.
import (
"io/ioutil"
"os"
"sync"
flatbuffers "github.com/google/flatbuffers/go"
)
// File operations
func SaveFlatBuffer(builder *flatbuffers.Builder, filename string) error {
data := builder.FinishedBytes()
return ioutil.WriteFile(filename, data, 0644)
}
func LoadFlatBuffer(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}
// Safe concurrent builder pool
type BuilderPool struct {
pool sync.Pool
}
func NewBuilderPool(initialSize int) *BuilderPool {
return &BuilderPool{
pool: sync.Pool{
New: func() interface{} {
return flatbuffers.NewBuilder(initialSize)
},
},
}
}
func (p *BuilderPool) Get() *flatbuffers.Builder {
return p.pool.Get().(*flatbuffers.Builder)
}
func (p *BuilderPool) Put(builder *flatbuffers.Builder) {
builder.Reset()
p.pool.Put(builder)
}
// Concurrent processing example
func ProcessMonstersAsync(monsters []MonsterData) [][]byte {
const numWorkers = 4
pool := NewBuilderPool(1024)
input := make(chan MonsterData, len(monsters))
output := make(chan []byte, len(monsters))
// Start workers
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
builder := pool.Get()
defer pool.Put(builder)
for monster := range input {
// Build FlatBuffer from monster data
result := buildMonster(builder, monster)
output <- result
builder.Reset()
}
}()
}
// Send work
go func() {
for _, monster := range monsters {
input <- monster
}
close(input)
}()
// Wait and collect results
go func() {
wg.Wait()
close(output)
}()
var results [][]byte
for result := range output {
results = append(results, result)
}
return results
}Complete Usage Example:
package main
import (
"fmt"
"io/ioutil"
"log"
flatbuffers "github.com/google/flatbuffers/go"
// Import generated package
"example/MyGame"
)
func main() {
// Create monster
builder := flatbuffers.NewBuilder(1024)
// Create components
name := builder.CreateString("Dragon")
pos := &MyGame.Vec3{X: 1.0, Y: 2.0, Z: 3.0}
posOffset := pos.Pack(builder)
// Create inventory
inventoryData := []uint8{1, 2, 3, 4, 5}
MyGame.MonsterStartInventoryVector(builder, len(inventoryData))
for i := len(inventoryData) - 1; i >= 0; i-- {
builder.PrependUint8(inventoryData[i])
}
inventory := builder.EndVector()
// Build monster
monster := MyGame.MonsterCreate(builder, posOffset, 200, 150, name, inventory)
// Finish buffer
builder.Finish(monster)
buffer := builder.FinishedBytes()
// Read the data back
readMonster := MyGame.GetRootAsMonster(buffer, 0)
fmt.Printf("Name: %s\n", readMonster.Name())
fmt.Printf("HP: %d\n", readMonster.Hp())
fmt.Printf("Mana: %d\n", readMonster.Mana())
position := readMonster.Pos(nil)
if position != nil {
fmt.Printf("Position: %.1f, %.1f, %.1f\n", position.X, position.Y, position.Z)
}
fmt.Printf("Inventory size: %d\n", readMonster.InventoryLength())
inventoryBytes := readMonster.InventoryBytes()
for i, item := range inventoryBytes {
fmt.Printf("Item %d: %d\n", i, item)
}
// Save to file
if err := ioutil.WriteFile("monster.bin", buffer, 0644); err != nil {
log.Fatal(err)
}
// Load from file
loadedBuffer, err := ioutil.ReadFile("monster.bin")
if err != nil {
log.Fatal(err)
}
loadedMonster := MyGame.GetRootAsMonster(loadedBuffer, 0)
fmt.Printf("Loaded name: %s\n", loadedMonster.Name())
}