Skip to content

Instantly share code, notes, and snippets.

@arl
Created April 27, 2022 18:13
Show Gist options
  • Save arl/1ded641f0d7d739386a9f79e59d650d3 to your computer and use it in GitHub Desktop.
Save arl/1ded641f0d7d739386a9f79e59d650d3 to your computer and use it in GitHub Desktop.
module github.com/arl/gobtest
go 1.19
package main
import (
"bytes"
"encoding/gob"
"fmt"
"log"
"time"
)
type Message interface{}
func encodeMessage(enc *gob.Encoder, msg Message) error {
err := enc.Encode(&msg)
if err != nil {
return fmt.Errorf("failed encoding Message %+v: %v", msg, err)
}
return nil
}
func decodeMessage(dec *gob.Decoder) (Message, error) {
var msg Message
err := dec.Decode(&msg)
if err != nil {
return nil, fmt.Errorf("failed decoding Message: %v", err)
}
return msg, nil
}
func decodeConcrete[T Message](dec *gob.Decoder) (T, error) {
var msg Message
err := dec.Decode(&msg)
if err != nil {
t := new(T)
return *t, fmt.Errorf("failed decoding Message: %v", err)
}
return msg.(T), nil
}
type Measure struct {
Timestamp time.Time
Name string
Type string
DisplayName string
Unit string
Data string
}
func NewMeasure() Measure {
return Measure{
Timestamp: time.Now(),
Name: "some name",
Type: "some type",
DisplayName: "some display name",
Unit: "some unit",
Data: "some data",
}
}
type Alert struct {
Timestamp time.Time
Name string
State string
Message string
}
func NewAlert() Alert {
return Alert{
Timestamp: time.Now(),
Name: "some name",
State: "some state",
Message: "some message",
}
}
func concrete() {
gob.RegisterName("measurement", Measure{})
gob.RegisterName("alert", Alert{})
wire := bytes.Buffer{}
enc := gob.NewEncoder(&wire)
encodeMessage(enc, NewMeasure())
encodeMessage(enc, NewAlert())
dec := gob.NewDecoder(&wire)
myMeasure, err := decodeConcrete[Measure](dec)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", myMeasure)
myAlert, err := decodeConcrete[Alert](dec)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", myAlert)
}
func dynamic() {
gob.RegisterName("measurement", Measure{})
gob.RegisterName("alert", Alert{})
wire := bytes.Buffer{}
enc := gob.NewEncoder(&wire)
encodeMessage(enc, NewMeasure())
encodeMessage(enc, NewAlert())
dec := gob.NewDecoder(&wire)
msg1, err := decodeMessage(dec)
if err != nil {
log.Fatalf("error decoding msg1: %v", err)
}
msg2, err := decodeMessage(dec)
if err != nil {
log.Fatalf("error decoding msg2: %v", err)
}
doSomethingDynamic := func(imsg Message) {
switch msg := imsg.(type) {
case Measure:
fmt.Printf("%+v\n", msg)
case Alert:
fmt.Printf("%+v\n", msg)
default:
panic("")
}
}
doSomethingDynamic(msg1)
doSomethingDynamic(msg2)
}
func main() {
// When you already know the type of the concrete message you're receveing.
concrete()
// When you can receive multiple types, and switch based on the final type.
dynamic()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment