Go Tips

Here lies my collection of random things I've learned how to do in Go.

Emulating Closed Sum-Type / Discriminated Unions using the AsAny Pattern

2025-05-04

OpenAI's Go library makes extensive use of this, and I quite like it.

The trick is to use a sealed-interface union wrapper. It's a struct with mutually-exclusive pointer fields plus an unexported marker interface. You don't use the wrapper directly; use constructors to instantiate new instances.

package main

import "fmt"

type Dog struct{}

func NewDog(d Dog) PetUnion {
	return PetUnion{OfDog: &d}
}

func (Dog) bark() { fmt.Println("bark") }

type Cat struct{}

func NewCat(c Cat) PetUnion {
	return PetUnion{OfCat: &c}
}

func (Cat) meow() { fmt.Println("meow") }

// keep this private
type anyPet interface {
	implAnyPetUnion()
}

func (Dog) implAnyPetUnion() {}
func (Cat) implAnyPetUnion() {}

type PetUnion struct {
	OfDog *Dog
	OfCat *Cat
}

func (u PetUnion) AsAny() anyPet {
	switch {
	case u.OfDog != nil:
		return u.OfDog
	case u.OfCat != nil:
		return u.OfCat
	}
	return nil
}

func Example() {
	pet := NewDog(Dog{})
	switch v := pet.AsAny().(type) {
	case *Dog:
		v.bark()
	case *Cat:
		v.meow()
	}
	// Output:
	// bark
}

Recurring Tasks

2025-04-28

package main

import "time"

func NewHourlyCron(f func()) {
    ticker := time.NewTicker(time.Hour)
    defer ticker.Stop()

    for {
        select {
        case <-ticker.C:
            f()
        }
    }
}

Format Time in Kitchen Time

2025-04-28

package main

import (
	"fmt"
	"time"
)

func Example() {
	fmt.Println(time.Now().Format(time.Kitchen))
	// Output:
	// 11:00PM
}

Capitalize Words

2025-04-28

package main

import (
	"fmt"

	"golang.org/x/text/cases"
	"golang.org/x/text/language"
)

func Capitalize(s string) string {
	return cases.Title(language.English).String(s)
}

func ExampleCapitalize() {
	fmt.Println(Capitalize("abcdef"))
	fmt.Println(Capitalize("hi there"))
	fmt.Println(Capitalize("CAPITALIZED"))

	// Output:
	// Abcdef
	// Hi There
	// Capitalized
}