Go
Resources
Notes
-
workspace (mono-repos) > module (dir with
go.modfile) > package (related.gofiles) -
Builtin functions: golang.org/pkg/builtin
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
// 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
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
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
mainfunc
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?
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)
}