My New Hugo Site

  1. Bash
    1. Filters
      1. grep
      2. Sed
      3. jq
    2. Shellspec
  2. Design
  3. Architectural Patterns
    1. Systemd
    2. Message Broker
    3. JSON-RPC
  4. Go
    1. Concurrency
    2. Web Applications
    3. Compound Data
    4. Json
    5. Go vs Erlang
  5. Prolog Cookbook
  6. Documentation
    1. Hugo
      1. Go Html Template
      2. Table of Contents
    2. HTML
    3. CSS
      1. Color
      2. Style Guides
      3. Layout
    4. Mathjax
  7. Visualization
    1. D3
      1. Venn Diagrams
    2. SVG
    3. Visjs
      1. Network
  8. Data
    1. Yaml
    2. Events
      1. JSON-LD
    3. JSON
      1. jCal
    4. SQL
  9. JavaScript

Go

Starting places

  1. A Tour of Go
  2. An Introduction to Programming in Go
  3. How to Write Go Code
  4. Effective Go
  5. Tutorials
  6. Documentation
  7. Style Guide

Project organisation

Workspaces

Tutorial: Getting started with multi-module workspaces

go work init ./hello

Modules

A module’s name is set in the root of the project directory in the go.mod file, eg:

./go.mod

module myapp

go 1.19

This file is generated as follows:

mkdir myapp
cd myapp
go mod init myapp
go: creating new go.mod: module myapp
...

The project root directory name doesn’t have to be myapp, but it’s probably a good convention.

myapp
├── go.mod
├── main.go
└── mypackage
    ├── function1.go
    ├── function1_test.go
    ├── function2.go
    └── function2_test.go

Packages

Rather than put everything in the main.go file, myapp can be split into packages which in turn can be split into any number of files.

It’s easiest to give each package its own subdirectory. All go files in a given subdirectory would start with the line

package mypackage

Clients of a package (eg main.go) import it as "myapp/mypackage"

main.go

package main

import (
	"fmt"
	"myapp/mypackage"
)

func main() {
	fmt.Println(mypackage.ReverseRunes("!oG ,olleH"))
}

Note that functions etc declared in packages need to be upercassed to be exported:

Note shared functions and variables must start with capital letters to be seen by other files, though modules sharing the same package name only have to be in the same directory, they don’t need to import each other.

A moduleN.go file looks like this:

// Package mypackages implements additional functions to manipulate UTF-8
// encoded strings, beyond what is provided in the standard "strings" package.
package mypackage

// ReverseRunes returns its argument string reversed rune-wise left to right.
func ReverseRunes(s string) string {
	r := []rune(s)
	for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}
	return string(r)
}

go test

Guide

Example driven development

go doc

Go Doc Comments

godoc -http=:6060

godocgo

https://dev.to/billylkc/parse-json-api-response-in-go-10ng

https://blog.alexellis.io/golang-json-api-client/

https://go.dev/doc/database/

https://pkg.go.dev/github.com/jackc/pgx/v4

https://pkg.go.dev/github.com/jackc/pgx

https://www.alexedwards.net/blog/introduction-to-using-sql-databases-in-go

https://www.alexedwards.net/blog/using-postgresql-jsonb

Q: What’s the advantage of “If with a short statement”? stackoverflow

if err := json.NewEncoder(w).Encode(todos); err != nil {
	panic(err)
}

A: Scoping. In the above example, err’s scope is limited to inside the if statement.

goroutines

channels

https://www.honeybadger.io/blog/go-web-services/

https://blog.logrocket.com/how-to-make-http-post-request-with-json-body-in-go/

Go commands

go get github.com/gin-gonic/gin install packages.

go doc encoding/json shows documentation for a given package.

go fmt foo.go converts foo.go into tab (4 spaces) indented and other style changes.

Modules

  1. Using Go Modules

A module is a collection of Go packages stored in a file tree with a go.mod file at its root. The go.mod file defines the module’s module path, which is also the import path used for the root directory, and its dependency requirements, which are the other modules needed for a successful build. Each dependency requirement is written as a module path and a specific semantic version.

$ go mod init example/hello
go: creating new go.mod: module example/hello

$ go run .

$ go help

$ go mod tidy
go: finding module for package rsc.io/quote
go: found rsc.io/quote in rsc.io/quote v1.5.2

Tutorial

Return and handle an error

Testing

Testable Examples in Go

Standard library

  1. encoding
    1. encoding/json
  2. io
  3. mime
    1. mime/multipart
  4. os
    1. os/exec
    2. os/signal
  5. net
    1. net/http
    2. net/mail
  6. errors
  7. log

Command-line flags

One or two minus signs may be used; they are equivalent.

Flag parsing stops just before the first non-flag argument ("-" is a non-flag argument) or after the terminator “–”.

server --port=3030 --pidfile=http.pid --workers=4
package main

import (
  "flag"
  "fmt"
)

func main() {
  portPtr := flag.Int("port", 8080, "port number")
  userPtr := flag.String("user", "nginx", "user")
  
  flag.Parse()
  fmt.Println("port:", *portPtr)
  fmt.Println("user:", *userPtr)
}

os

func WriteFile(name string, data []byte, perm FileMode) error

type Page struct {
    Title string
    Body  []byte
}

func (p *Page) save() error {
    filename := p.Title + ".txt"
    return os.WriteFile(filename, p.Body, 0600)
}

func main() {
    p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
    p1.save()
}

func ReadFile(name string) ([]byte, error)

func loadPage(title string) (*Page, error) {
    filename := title + ".txt"
    body, err := os.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    return &Page{Title: title, Body: body}, nil
}

func main() {
    // p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
    // p1.save()
    p2, _ := loadPage("TestPage")
    fmt.Println(string(p2.Body))
}

net/http

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func ListenAndServe(addr string, handler Handler) error

func main() {
	...
    log.Fatal(http.ListenAndServe(":8080", nil))
}

type Request

type Request struct {
	Method string
	URL *url.URL
	Proto      string // "HTTP/1.0"
	ProtoMajor int    // 1
	ProtoMinor int    // 0
	Header Header
	Body io.ReadCloser
	GetBody func() (io.ReadCloser, error)
	ContentLength int64
	TransferEncoding []string
	Close bool
	Host string
	Form url.Values
	PostForm url.Values
	MultipartForm *multipart.Form
	Trailer Header
	RemoteAddr string
	RequestURI string
	TLS *tls.ConnectionState
	Response *Response
}

func (*Request) ParseForm

func (*Request) FormValue

func (*Request) PostFormValue