davideisinger.com

My personal website
Log | Files | Refs | README

index.md (8974B)


      1 ---
      2 title: "Golang"
      3 date: 2023-05-08T09:54:48-04:00
      4 draft: false
      5 references:
      6 - title: "Why David Yach Loves Go"
      7   url: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
      8   date: 2023-06-13T14:51:05Z
      9   file: cloud-google-com-windxx.txt
     10 - title: "One process programming notes (with Go and SQLite)"
     11   url: https://crawshaw.io/blog/one-process-programming-notes
     12   date: 2023-06-13T14:49:51Z
     13   file: crawshaw-io-k5slfj.txt
     14 - title: "Go Project Layout"
     15   url: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
     16   date: 2023-06-13T15:00:02Z
     17   file: medium-com-efpmux.txt
     18 - title: "Gopher Wrangling. Effective error handling in Go | Stephen's Tech Blog"
     19   url: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
     20   date: 2023-06-20T16:25:12Z
     21   file: stephenn-com-kbiijs.txt
     22 - title: "Effective Go - The Go Programming Language"
     23   url: https://go.dev/doc/effective_go
     24   date: 2023-07-12T03:17:03Z
     25   file: go-dev-vfin4x.txt
     26 ---
     27 
     28 I find [Go][1] 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.
     29 
     30 * I like that it compiles, and have no desire to install someone else's Python
     31 * It just seems to hit the right balance of productivity, performance, simplicity, safety
     32 * The language (and the tech built with the language) just seems built to last
     33 
     34 [1]: https://go.dev/
     35 
     36 ### Questions to Answer
     37 
     38 * How to organize large(r) codebases
     39 * Goroutines / concurrency
     40 * Dev tooling
     41 * How to read/write JSON
     42 * How to validate with JSON Schema
     43   * <https://github.com/qri-io/jsonschema>
     44 * Testing
     45 
     46 ### Projects I like
     47 
     48 * [Hugo][2]
     49 * [Caddy][3]
     50 * [PocketBase][4]
     51 * [SyncThing][5]
     52 * [Restic][6]
     53 * [Gotenberg][7]
     54 * [Shiori][8]
     55 * [Listmonk][9]
     56 
     57 [2]: https://gohugo.io/
     58 [3]: https://caddyserver.com/
     59 [4]: https://pocketbase.io/
     60 [5]: https://syncthing.net/
     61 [6]: https://restic.net/
     62 [7]: https://gotenberg.dev/
     63 [8]: https://github.com/go-shiori/shiori
     64 [9]: https://listmonk.app/
     65 
     66 ### Project Ideas
     67 
     68 * Bookmarking app (Pinboard replacement)
     69 * Note-taking / journaling app
     70 * [StevieBlocks][10]
     71 
     72 {{<dither project1.png "374x">}}Handwritten notes outlining a Go project plan: build a web service that accepts POST JSON, validates it against a schema, replies with errors if invalid or 200 if valid, and then stores the data in SQLite.{{</dither>}}
     73 
     74 [10]: https://gist.github.com/dce/f975cb21b50a2cf998bf7230cbf89d85
     75 
     76 ### Resources
     77 
     78 * [Standard Go Project Layout][11]
     79 * [The files & folders of Go projects][12]
     80 * [Why David Yach Loves Go][13]
     81 * [One process programming notes (with Go and SQLite)][14]
     82 * [Go Project Layout][15]
     83 * [Gopher Wrangling. Effective error handling in Go][16]
     84 * [Effective Go][17]
     85 
     86 [11]: https://github.com/golang-standards/project-layout
     87 [12]: https://changelog.com/gotime/278
     88 [13]: https://cloud.google.com/blog/products/application-modernization/why-david-yach-loves-go
     89 [14]: https://crawshaw.io/blog/one-process-programming-notes
     90 [15]: https://medium.com/golang-learn/go-project-layout-e5213cdcfaa2
     91 [16]: https://stephenn.com/2023/06/gopher-wrangling.-effective-error-handling-in-go/
     92 [17]: https://go.dev/doc/effective_go
     93 
     94 ### Notes
     95 
     96 * Regular Expressions
     97   * Compile with `regexp.MustCompile` (no need to check for error)
     98   * Strings denoted by backticks don't escape; use these for regular expressions
     99   * For case-insensitive matching, start the expression with `(?i)`
    100 * [Unnamed parameters][18]
    101 
    102   > Unnamed parameters are perfectly valid. The [Parameter declaration](https://golang.org/ref/spec#ParameterDecl) from the spec:
    103   >
    104   > ```
    105   > ParameterDecl  = [ IdentifierList ] [ "..." ] Type .
    106   > ```
    107   >
    108   > As you can see, the `IdentifierList` (the identifier name or names) is in square brackets, which means it's _optional_. Only the `Type` is required.
    109   >
    110   > 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](https://stackoverflow.com/questions/31377433/getting-method-parameter-names-in-golang/31377793#31377793)
    111 
    112 * [Named result parameters][19]
    113 
    114   > 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.
    115 
    116 * Type Conversion & Assertion
    117   * Built-in functions for conversion (`float64`, `strconv.Atoi`)
    118   * `if v, ok := fnb.(FancyNumber); ok {` (`v` is a `FancyNumber` if `ok` is true)
    119   * `switch v := i.(type) {` (case per type, `v` is `i` cast to that type)
    120 * [Custom error types][20]
    121 
    122   > 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 the `Error() string` method with a pointer receiver, see this [Stackoverflow comment](https://stackoverflow.com/a/50333850) to learn about the reasoning. Note that this means you need to return a pointer to your custom error otherwise it will not count as `error` because the non-pointer value does not provide the `Error() string` method.
    123 
    124 * [Maps][21]
    125 
    126   > A Go map type looks like this: `map[KeyType]ValueType`
    127 
    128   > To initialize a map, use the built in `make` function: `m = make(map[string]int)`
    129 
    130   > 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 is `int`, so the zero value is `0`.
    131 
    132   > A two-value assignment tests for the existence of a key: `i, ok := m["route"]`
    133 
    134   * [Insertion order has no effect on the order keys/values are retrieved in a `range` query][22]
    135 
    136     > The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next.
    137 
    138   * [`new` allocates zeroed storage for a new item or type whatever and then returns a pointer to it.][23]
    139 
    140 * First-class functions
    141   * Go supports first-class functions (functions as arguments and return values of other functions)
    142   * Go has closures (so variables defined inside a function that returns a function get closed over)
    143   * Go has anonymous functions (`func` w/o name)
    144 * Slices
    145   * Use `append` to add to a slice; this creates a new slice, so you have to capture the return value (`s = append(s, 100)`)
    146 * `math/rand`
    147   * `rand.Intn`: random integer between 0 and the specified int
    148   * `rand.Float64`: random float between 0.0. and 1.0
    149   * `rand.Shuffle`: randomize an array/slice; takes a length and a swap function
    150 * Stringers
    151   * Define a `String() string` method for types so that `fmt` knows how to stringify them
    152   * E.g. `fmt.Sprintf("%s", yourThing)` will call `yourThing`'s `String()` function
    153 * Structs
    154   * [What Are Golang's Anonymous Structs?][24]
    155 
    156   > 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.
    157   >
    158   > 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.
    159   >
    160   > To create an anonymous struct, just instantiate the instance immediately using a second pair of brackets after declaring the type.
    161 
    162 * [Time][25]
    163   * `time.Duration` -- `time.Second * 1e9` is a duration of one billion seconds
    164   * `1e9` is the same as `1.0*math.Pow(10, 9)`
    165 * Runes
    166   * `unicode.IsLetter` -- test if rune is a letter
    167   * `strings.ContainsRune` -- test if string contains letter (`strings.ContainsRune(s[i+1:], c)`)
    168 * `log.Println` -- print out anything (like a data structure)
    169 * `strings.Map` -- map over a string
    170   * `return strings.Map(func(r rune) rune { return mapping[r] }, dna)`
    171 * Generics
    172   * Use `[]` to define types
    173   * `func keep[T int | []int | string](in []T, filter func(T) bool) (out []T) {`
    174   * [Use `~` to allow "inheriting" (?) types][26]
    175 
    176   > In Go generics, the ~ tilde token is used in the form ~T to denote the set of types whose underlying type is T.
    177 
    178 * [Type Aliases][27]
    179 
    180   > 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.
    181 
    182 [18]: https://stackoverflow.com/a/40951013
    183 [19]: https://go.dev/doc/effective_go#named-results
    184 [20]: https://exercism.org/tracks/go/concepts/errors
    185 [21]: https://go.dev/blog/maps
    186 [22]: https://go.dev/ref/spec#RangeClause
    187 [23]: https://stackoverflow.com/a/34543716
    188 [24]: https://blog.boot.dev/golang/anonymous-structs-golang/
    189 [25]: https://pkg.go.dev/time
    190 [26]: https://stackoverflow.com/a/70890514
    191 [27]: https://yourbasic.org/golang/type-alias/