mariamihai / go-tutorials

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Go tutorials

Table of Content

Tutorials

Follow along for go.dev tutorials:

Follow along for freeCodeCamp tutorials. Tutorial's README here.

Commands

Initialize a new module

here

go mod init [module-path] go mod init /

  • creates a new go.mod file in current directory
  • the file must not exist already

Add missing dependencies or remove unused ones

here

go mod tidy [-e] [-v] [-go=version] [-compat=version]

  • [-e] - continue with errors
  • [-v] - info for removed modules
  • [-go] - sets version, enable or disable module graph pruning and module loading based on version (changes from go 1.17)
  • [-compat] - set the version to be checked for compatibility

Edit and format go.mod file

here

go mod edit [editing flags] [-fmt|-print|-json] [go.mod]

Example:

go mod edit -replace random-prefix/greetings=../greeting

  • [editing flags]
    • -module, -go=version, -require=path@version / -droprequire=path, -exclude=path@version / -dropexclude=path@version, -replace=old[@v]=new[@v], -dropreplace=old[@v], -retract=version / -dropretract=version
    • can have multiple editing flags
  • [-fmt]
    • format
    • implicit as part of other go mod edit commands
  • [-print]
    • print as text instead of writing to disk
  • [-json]
    • returns a json instead of writing to disk

Copy dependencies with mod vendor

here and here

go mod vendor [-e] [-v] [-o outdir]

  • [-v]
    • print the names of vendored modules and packages to standard error
  • [-e]
    • causes vendor to attempt to proceed despite errors encountered while loading packages
  • [-o]
    • causes vendor to create the vendor directory at the given path instead of "vendor"

Run the app

here

go run [build flags] [-exec xprog] package [arguments...]

  • compile and run the main go package
  • single package: go run .
  • with path: go run my/cmd

Run tests

here

go test [build/test flags] [packages] [build/test flags & test binary flags]

  • run tests for files matching the filename pattern *_test.go and functions named TestXxx (after Test there needs to be an upper case - exported name)
  • these files can contain tests, benchmark or example functions

More info:

go help testfunc

Build

here

go build [-o output] [build flags] [packages]

  • compiles the packages, along with their dependencies, doesn't install the results
  • ignores files that end in _test.go

Install

here

go install [build flags] [packages]

Format files

here

go fmt [-n] [-x] [packages]

  • [-n]
    • prints commands that would be executed
  • [-x]
    • prints commands as they are executed
  • [-mod]
    • sets which module download mode to use: readonly or vendor

Update packages to use new APIs

go fix [-fix list] [packages]

  • [-fix]
    • sets a comma-separated list of fixes to run. The default is all known fixes.

Get mistakes with go vet

here

go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]

  • [-n]
    • prints commands that would be executed
  • [-x]
    • prints commands as they are executed
  • [-vettool=prog]
    • selects a different analysis tool with alternative or additional checks

Example:

  • the 'shadow' analyzer can be built and run:

go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow go vet -vettool=$(which shadow)

Remove files and clean cache

go clean [clean flags] [build flags] [packages]

Example:

go clean -i

  • remove the corresponding installed archive or binary added by go install

List packages and modules

here

go list [-f format] [-json] [-m] [list flags] [build flags] [packages]

Example:

  • the installation path after compiling caller into an executable

go list -f '{{.Target}}'

  • an array will all available .go files under current path

go list -f '{{.GoFiles}}'

  • print the package data in JSON format

go list -json

Generate documentation

here

go doc [doc flags] [package|[package.]symbol[.methodOrField]]

Example:

  • documentation for formatting files

go doc cmd/gofmt

  • show all documentation for the package

go doc -all

Debugging

The standard debugger for Go applications is Delve - commands

go install github.com/go-delve/delve/cmd/dlv@latest

Check it was correctly installed with dlv version or with a path ~/go/bin/dlv.

Using Delve:

dlv debug main.go break bp1 main.main:3 condition bp1 i == 2 continue next step stepout restart exit

print set = locals whatis

Linting & fixing common problems

golint (deprecated)

revive

here

  • provides support for controlling which rules are applied

go install github.com/mgechev/revive@latest revive

  • you can disable or enable a rule in code:
// revive:disable:exported
// revive:enable:exported
  • the configuration file for this linter is revive.toml
    • options here
    • recoomented configuration here
  • run the linter with configuration file

revive -config revive.toml

go vet

go vet go vet main.go go vet -json main.go

go vet -assign=false go vet -assign

The language

Exported name

  • a function named starting with a capital letter can be called by a function not in the same package
  • if calling a function from a different package with a lower letter you get an error: cannot refer to unexported name xxxxx

:= operator

  • used for declaring and initializing a variable
message := fmt.Sprintf("Hi, %v. Welcome!", name)

// Same as
var message string
message = fmt.Sprintf("Hi, %v. Welcome!", name)

Multiple return values

here

// Definition
func Hello(name string) (string, error) {
	if name == "" {
		return "", errors.New("empty name")
	}

	message := fmt.Sprintf("Hi, %v. Welcome!", name)

	return message, nil
}

// Calling the function
message, err := greetings.Hello("")

Named results

here

  • named results are initialized
func ReadFull(r Reader, buf []byte) (n int, err error) {
    for len(buf) > 0 && err == nil {
        var nr int
        nr, err = r.Read(buf)
        n += nr
        buf = buf[nr:]
    }
    return
}

Arrays and slices

here

Arrays

  • the array's size is fixed
  • the length is part of its type ([4]int is distinct and incompatible with [3]int)
  • can be indexed - s[n] will return the nth element, starting from 0
var a [4]int
a[0] = 1

i := a[0] // i = 1
  • arrays don't need to be initialized explicitly
  • the arrays are values, the variable is not a pointer to the first element but represents the entire array
  • assigning an array value makes a copy of the content
b := [2]string{"Penn", "Teller"}

// or
b := [...]string{"Penn", "Teller"}

Slices

letters := []string{"a", "b", "c"}

// or
var s[]byte
// Using func make([]T, len, cap) []T
s = make([]byte, 5, 5) // s = []byte{0, 0, 0, 0, 0}

// or
s = make([]byte, 5)
  • can form a slice from "slicing" an existing slice or array
b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}

// b[1:4] == []byte{'o', 'l', 'a'}

// b[:2] = []byte{'g', 'o'}
// b[2:] = []byte{'l', 'a', 'n', 'g'}
// b[:] = b

// Create slíce from array
golang := [6]byte{'g', 'o', 'l', 'a', 'n', 'g'}
s := golang[:]
  • b[1:4] shares the same storage as b
  • doesn't copy the slice's data, but it creates a new slice value that points to the original array
d := [byte]{'r', 'o', 'a', 'd'}
e := d[2:]

e[1] = 'm'

// d = [byte]{'r', 'o', 'a', 'm'}
// e = [byte]{'a', 'm'}
  • getting the length (the number of elements referred to by the slice) and the capacity (the number of elements in the underlying array) with len(s) and cap(s)

  • can't grow a slice beyond its capacity and can't index outside the bounds - these cause runtime panic

  • slices can't be re-sliced below 0

  • copy data from a source slice to a destination, returning the number of elements copied

func copy (dest, src []T) int

  • append the elements x to the end of the slice s; it will take care of increasing the size of the slice if needed

func copy (s []T, x ...T) []T

Example:

a := make([]int, 1) // a = []int{0}

a = appent(a, 1, 2, 3) // a = []int{0, 1, 2, 3}
  • append one slice to another with ... to expand the second slice
a := []int{1, 2, 3}
b := []int{4, 5, 6}

a = append(a, b...) // a = append(a, b[0], b[1], b[2])

The init function

  • the init functions are automatically executed at program setup
  • used for initializations that can't be done by declarations, verifications of program state
  • first the imported packages are initialized, then the global variables are initialized, then the init function is called
  • each file can have multiple init functions

Random

go:embed

  • documentation and article link
  • include the contents of arbitrary files and directories with //go:embed FILENAME(S) followed by a string or []byte variable for one file or embed.FS for a group of files
  • patterns like files/*.html will also work (but not **/*.html recursive globbing)

Simple use

package main

import (
    _ "embed"
    "fmt"
    "strings"
)

var (
    Version string = strings.TrimSpace(version)
    //go:embed version.txt
    version string
)

func main() {
    fmt.Printf("Version %q\n", Version)
}

Use conditionally

Include version information conditionally based on whether a build tag is passed to the go tools:

// version_dev.go file:

//go:build !prod
// +build !prod

package main

var version string = "dev"

Run:

$ go run .
Version "dev"
// version_prod.go file:

//go:build prod
// +build prod

package main

import (
    _ "embed"
)

//go:embed version.txt
var version string

Run:

$ go run -tags prod .
Version "0.0.1"

Gotchas

  • need to import the embed package in any file that uses an embed directive
  • can only use //go:embed for variables at the package level, not within functions or methods
  • when you include a directory, it won’t include files that start with . or _, but if you use a wildcard, like dir/*, it will include all files that match, even if they start with . or _
    • use //go:embed dir or //go:embed dir/*.ext for security reasons (otherwise you will accidentally include Mac OS's .DS_Store)
  • for security reasons, Go also won’t follow symbolic links or go up a directory when embedding

go:generate

  • article link
  • automate the running of tools to generate source code before compilation

Alternative - using -ldflags

Can use -ldflags to override string values:

package main

import (
	"fmt"
)

var VersionString = "unset"

func main() {
	fmt.Println("Version:", VersionString)
}

Run:

$ go run main.go
Version: unset

$ go run -ldflags '-X main.VersionString=1.0' main.go
Version: 1.0

# Can use git commit hash:
$ go run -ldflags "-X main.VersionString=`git rev-parse HEAD`" main.go
Version: db5c7db9fe3b632407e9f0da5f7982180c438929

# Need single quote if there is a space
$ go run -ldflags "-X 'main.VersionString=1.0 (beta)'" main.go
Version: 1.0 (beta)

# Ca use the standard Unix date command
$ go run -ldflags "-X 'main.VersionString=`date`'" main.go
Version: Sun Nov 27 16:42:10 EST 2016

go:generate use

package project

//go:generate echo Hello, Go Generate!

func Add(x, y int) int {
	return x + y
}

Run:

$ go generate
Hello, Go Generate!

Can be used with tools like stringer, jsonenums and schematyper.

Links

Build Constraints

flag.Func

Testing and linting in pipeline

Project here for GitHub Actions use.

Other resources to check

Exercises and challenges:

About


Languages

Language:Go 100.0%