Notes > Golang
I find Go really compelling, even though it’s not super applicable to my job. When evaluating a new tool, I find I’m weirdly biased to things written in Go.
- I like that it compiles, and have no desire to install someone else’s Python
- It just seems to hit the right balance of productivity, performance, simplicity, safety
- The language (and the tech built with the language) just seems built to last
Questions to Answer
- How to organize large(r) codebases
- Goroutines / concurrency
- Dev tooling
- How to read/write JSON
- How to validate with JSON Schema
- Testing
Projects I like
Project Ideas
- Bookmarking app (Pinboard replacement)
- Note-taking / journaling app
- StevieBlocks
Resources
- Standard Go Project Layout
- The files & folders of Go projects
- Why David Yach Loves Go
- One process programming notes (with Go and SQLite)
- Go Project Layout
- Gopher Wrangling. Effective error handling in Go
- Effective Go
Notes
Regular Expressions
- Compile with
regexp.MustCompile
(no need to check for error) - Strings denoted by backticks don’t escape; use these for regular expressions
- For case-insensitive matching, start the expression with
(?i)
- Compile with
Unnamed parameters are perfectly valid. The Parameter declaration from the spec:
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
As you can see, the
IdentifierList
(the identifier name or names) is in square brackets, which means it’s optional. Only theType
is required.The reason for this is because the names are not really important for someone calling a method or a function. What matters is the types of the parameters and their order. This is detailed in this answer: Getting method parameter names in Golang
The return or result “parameters” of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.
Type Conversion & Assertion
- Built-in functions for conversion (
float64
,strconv.Atoi
) if v, ok := fnb.(FancyNumber); ok {
(v
is aFancyNumber
ifok
is true)switch v := i.(type) {
(case per type,v
isi
cast to that type)
- Built-in functions for conversion (
Usually, a struct is used to create a custom error type. By convention, custom error type names should end with
Error
. Also, it is best to set up theError() string
method with a pointer receiver, see this Stackoverflow comment to learn about the reasoning. Note that this means you need to return a pointer to your custom error otherwise it will not count aserror
because the non-pointer value does not provide theError() string
method.A Go map type looks like this:
map[KeyType]ValueType
To initialize a map, use the built in
make
function:m = make(map[string]int)
This statement retrieves the value stored under the key
"route"
and assigns it to a new variable i:i := m["route"]
. If the requested key doesn’t exist, we get the value type’s zero value. In this case the value type isint
, so the zero value is0
.A two-value assignment tests for the existence of a key:
i, ok := m["route"]
Insertion order has no effect on the order keys/values are retrieved in a
range
queryThe iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.
new
allocates zeroed storage for a new item or type whatever and then returns a pointer to it.
First-class functions
- Go supports first-class functions (functions as arguments and return values of other functions)
- Go has closures (so variables defined inside a function that returns a function get closed over)
- Go has anonymous functions (
func
w/o name)
Slices
- Use
append
to add to a slice; this creates a new slice, so you have to capture the return value (s = append(s, 100)
)
- Use
math/rand
rand.Intn
: random integer between 0 and the specified intrand.Float64
: random float between 0.0. and 1.0rand.Shuffle
: randomize an array/slice; takes a length and a swap function
Stringers
- Define a
String() string
method for types so thatfmt
knows how to stringify them - E.g.
fmt.Sprintf("%s", yourThing)
will callyourThing
’sString()
function
- Define a
Structs
An anonymous struct is just like a normal struct, but it is defined without a name and therefore cannot be referenced elsewhere in the code.
Structs in Go are similar to structs in other languages like C. They have typed collections of fields and are used to group data to make it more manageable for us as programmers.
To create an anonymous struct, just instantiate the instance immediately using a second pair of brackets after declaring the type.
time.Duration
–time.Second * 1e9
is a duration of one billion seconds1e9
is the same as1.0*math.Pow(10, 9)
Runes
unicode.IsLetter
– test if rune is a letterstrings.ContainsRune
– test if string contains letter (strings.ContainsRune(s[i+1:], c)
)
log.Println
– print out anything (like a data structure)strings.Map
– map over a stringreturn strings.Map(func(r rune) rune { return mapping[r] }, dna)
Generics
- Use
[]
to define types func keep[T int | []int | string](in []T, filter func(T) bool) (out []T) {
- Use
~
to allow “inheriting” (?) types
In Go generics, the ~ tilde token is used in the form ~T to denote the set of types whose underlying type is T.
- Use
An alias declaration doesn’t create a new distinct type different from the type it’s created from. It just introduces an alias name T1, an alternate spelling, for the type denoted by T2.
References
- “Why David Yach Loves Go”; backed up 2023-06-13 14:51:05 UTC
- “One process programming notes (with Go and SQLite)”; backed up 2023-06-13 14:49:51 UTC
- “Go Project Layout”; backed up 2023-06-13 15:00:02 UTC
- “Gopher Wrangling. Effective error handling in Go | Stephen's Tech Blog”; backed up 2023-06-20 16:25:12 UTC
- “Effective Go - The Go Programming Language”; backed up 2023-07-12 03:17:03 UTC