Go Tips ¶
Here lies my collection of random things I've learned how to do in Go.
Helpful Links ¶
Marking a Context as Done with a Signal ¶
2025-07-12
The signal
package has a useful function called NotifyContext
that will notify the Done
channel of the Context
when one of the listed signals is received by the running process.
Watch out! When you use this, the exit
method will no longer be called when an interrupt is received, so you'll need to call it yourself.
package main
import (
"context"
"fmt"
"os"
"os/signal"
)
func main() {
ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
fmt.Println("press Ctrl-C to exit...")
// waits
<-ctx.Done()
os.Exit(0)
}
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
}