Last updated about 1 week ago

Go

Resources

Notes

How to

Read from console/terminal

ip := bufio.NewReader(os.Stdin)
fmt.Print("Enter something: ")
name, _ := ip.ReadString('\n')
fmt.Println("You entered: ", name)

Use the regexp package

pkg.go.dev/regexp

// Quick match
matched, err := regexp.MatchString(`foo.*`, "seafood")
fmt.Println(matched, err)

// Find a string
re := regexp.MustCompile(`foo.?`)
fmt.Printf("%q\n", re.FindString("seafood fool"))

// Find capture groups
re := regexp.MustCompile(`a(x*)b`)
fmt.Printf("%q\n", re.FindAllStringSubmatch("-ab-", -1))
fmt.Printf("%q\n", re.FindAllStringSubmatch("-axxb-", -1))

// Replace A with X, B with Y, C with Z
replaceMap := map[string]string{"A": "X", "B": "Y", "C": "Z"}
re := regexp.MustCompile(`(A|C|G|T)`)
re.ReplaceAllStringFunc("ABCCCBBAAABC", func(s string) string { return replaceMap[s] })

Write a Test

go.dev/add-a-test gobyexample/testing

In short, to test a func Fn in package mx.go, create a file mx_test.go with same package, then add a TestFn function that takes in a *testing.T like so:

func TestFn(t *testing.T) {
    want := "expected"
    got, err := mx.Fn();
    if err != nil {
        t.Fatalf(err) // <- Unexpected error
    }
    if want != got {
        t.Errorf("Expected ", want, ", got", got); // <-- Logical error
    }
    // Fatalf stops test run, Errorf shows error but continues other tests
    // Use each where it makes sense
}

You can then test this with go test . assuming a go.mod is in place.

Compile time assertion for a type implementing an interface

TL;DR: To ensure that a type T satisfies interface I, add this one-liner:

var _ I = (*T)(nil)

Long story -

Okay, this was a bit of a head-scratcher for me, so I’ll explain it from the top as I understood it:

Premise: Go is “duck-typed” (like Python), in the sense you don’t explicitly tell a type to implement an interface (like say, Java). Rather you write the methods as required by the interface and the type satisfies that interface implicitly.

// Say we have an interface defined somewhere like so
type Xer interface  { X() }

// And a function that relies on the above
func DoX(x Xer) { x.X(); }

// In some other file, we have some type
type A struct {}

// And we want to pass an instance of it
// to the function that consumes the interface
func unrelatedCall() { a := A{}; DoX(a) }

// All it takes is for the type to implement an interface is to define the behaviour
func (a A) X() {}

Problem: This is all fine and dandy when the interface definition, consumer function and the struct itself are well-known to you (like in a small code-base). You can eyeball it to ensure everything is on the up and up. When you can’t, how do you ensure and let others - humans and machines both, know as well that yes, A actually satisfies Xer and you can use it in functions that consume it?

Solution: That is where this magical line comes into play -

var _ Xer = (*A)(nil)

Alright, let’s break it down. Remember basic variable definition? var <name> <type> = <value> . Well, we don’t actually need a name because we ain’t gonna use it. So _ it. type is the interface we’re ensuring is satisfied by value. But we don’t want to initialize a value either, so we make a nil pointer to it.

And thus, if A does not implement Xer by way of X() method, we will get an error. More importantly, any packages (and linters, lsps, etc) that use A now know that it implements Xer!

Use go run as a shell script

stackoverflow.com/whats-the-appropriate-go-shebang-line

Add this at the top of file (even before package main):

//usr/bin/env go run "$0" "$@"; exit "$?"

chmod and then your ./script.go just works!

IMPORTANT! go will complain if you have multiple files with main func

Ignore multiple main functions in same package

Best option I found is to simply keep packages in different directories as different modules; You can then go install . them to run from wherever.

Structure a project?

For all projects, start with:

mkdir project-name && cd project-name
go mod init whatever/project-name
touch project-name.go # package main

If it’s a short script, this is enough. If you need to split code, say separate some utilities:

mkdir internal/utils/utils.go # contains a function X

and inside project-name.go, import utils like so:

// Import the internal utils package
import "whatever/project-name/internal/utils"
// And use the function like so:
utils.X()

If it’s an CLI/API, by convention that code goes into a cmd dir, while for a website, it goes into a web dir (sibling to internal).

How to gracefully shut down a go app?

https://go.dev/wiki/SignalHandling

package main

func main() {
    // Make a context tha returns a cancel fn
	ctx, cancelJobs := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancelJobs()

    // Create a chan that wait on a signal
    sig := make(chan os.Signal, 1)
	signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM)

    // At the end of main, wait on the chan for the signal
    <-sig
	log.Println("Shutting down gracefully")
}

How to use a template (in html web-server)?

See dev-log/go and pingmon/web for reference. See go.dev/text/template and go.dev/html/template for documentation.

How to run an external command?

See go.dev/os/exec for package docs

// For normal run, but show error if not:
cmd := exec.Command("echo", "hello, world!")
if err := cmd.Run(); err != nil {
    log.Println(err)
}

// For when combined (stdour/err) output is needed:
cmd := exec.Command("echo", "hello, world!")
if op, err := cmd.CombinedOutput(); err != nil {
    log.Fatalf("Error while running cmd: %v", err)
} else {
    log.Println(string(op))
}

// For when a cmd struct is necessary (for customization):
cmd := exec.Cmd{
    // See https://pkg.go.dev/os/exec#Cmd
    Path:   "/bin/echo",
    Args:   []string{"echo", "hello,", "world"},
    Stdout: os.Stdout,
}
if err := cmd.Run(); err != nil {
    log.Fatalf("Error while running cmd: %v", err)
}

Use go:stringer, and when?

Use go:embed, and when?