Go (Programming Language) Reference
Kip Landergren
(Updated: )
My cheat sheet for the Go programming language covering installation, basic commands, and resources.
Contents
- Tips
- Tooling
- Writing Software in Go
- WebAssembly
- Go Terminology
-
Frequently Asked Questions (FAQ)
- What is the difference between a nil slice and an empty slice?
- Does a map resize down after deletions?
- Can you initialize a map with a default value?
- What is the size of Go’s int? What is the width of Go’s int?
- What does the “A” stand for in strconv.Atoi() (and strconv.Itoa())?
- Does Go have a ternary operator?
- How to print my object as a string?
- Does Go have a Set data structure?
- Resources
-
go-study
- README.md
- lang/constants.go
- lang/statements/iteration.go
- lang/statements/switch.go
- lang/types/basic_types.go
- lang/types/map.go
- lang/types/slice.go
- lang/types/string.go
- lang/variables/swap.go
- personal_conventions.go
- stdlib/errors_demo/errors.go
- stdlib/fmt_demo/fmt.go
- stdlib/fmt_demo/formatting_verbs.go
- stdlib/log_demo/log.go
- stdlib/os_demo/os.go
- stdlib/sort_demo/sort.go
- stdlib/strconv_demo/strconv.go
- stdlib/strings_demo/strings.go
- stdlib/unicode_demo/unicode.go
- tricks/bit_shifting_tricks.go
- tricks/math_tricks.go
- tricks/slice_tricks.go
- x/exp/maps/maps.go
- x/exp/slices/slices.go
Tips
- start coding right away:
- Go rewards writing code early and modifying / refactoring as you better understand the problem
- refer to official package documentation
- refer to the language specification
Tooling
The go Tool
go bug | start a bug report |
go build | compile packages and dependencies (but do not install the results) |
go clean | remove object files and cached files |
go doc | show documentation for package or symbol |
go env | print Go environment information |
go fix | update packages to use new APIs |
go fmt | gofmt (reformat) package sources |
go generate | generate Go files by processing source |
go get | add dependencies to current module and install them |
go install | compile and install packages and dependencies |
go list | list packages or modules |
go mod | module maintenance |
go run | compile and run Go program |
go test | test packages |
go tool | run specified go tool |
go version | print Go version |
go vet | report likely mistakes in packages |
go build
-C dir | change to dir before running the command |
-o output | force build to write the resulting executable or object to the named output file or directory. If the named output is an existing directory or ends with a slash or backslash, then any resulting executables will be written to that directory. |
go build -o ./bin foo.go
go env
Print Go environment information:
go env
go help
go help
go help [command]
go help [command] [subcommand]
go mod
Edit go.mod to change Go version:
go mod edit -go=1.23.3
gopls
Installation
go install golang.org/x/tools/gopls@latest
Configuration
Review official settings documentation.
Environment Variables
GOPATH | defaults to $HOME/go on Unix |
GOBIN | defaults to $GOPATH/bin |
GOMODCACHE | defaults to $GOPATH/pkg/mod |
GOPATH is used by:
- go install:
- to install binaries to $GOBIN
- go get to cache the downloaded:
- modules to $GOMODCACHE
- checksum database state to $GOPATH/pkg/sumdb
Note: GOPATH was previously used for “GOPATH development mode” or “GOPATH mode” which was superceded by Go modules.
Writing Software in Go
Language Idioms
Zero Values
When creating a new type, construct it such that its zero value is useable without further setup.
comma-ok
iterator.More()
Table Testing
See “Testing” section.
Packages
Structure and naming conventions:
- prefer singular; avoid plural (e.g. prefer “connection” vs “connections”)
- avoid common names (e.g. “util”)
- avoid dashes
- lower-case only
- organize by function, not by source layout (e.g. “http/connection” vs “src/models/connection”)
More information available from:
- Effective Go’s section on naming
- The Go Blog’s post on package names
- rakyll’s notes about package style
Testing
Test all packages in a module, recursively:
go test -v ./...
- prefer t.Log() to fmt.Println()
- use subtests
- employ table testing (AKA data provider pattern)
- use the correct API:
- T.Error() and T.Errorf() when execution should continue for the current test
- T.Fatal() and T.Fatalf() when execution should stop for the current test and continue at the next
Table testing example:
package main
import (
"testing"
)
func Test_NewInstructions(t *testing.T) {
// put our test cases into a "table" where the map key represents the name
// and the struct{} represents the test case
testCases := map[string]struct {
line string
instruction Instruction
}{
"y direction": {
line: "fold along y=7",
ins: Instruction{
Raw: "fold along y=7",
Dir: "up",
Value: 7,
},
},
"x direction": {
line: "fold along x=5",
ins: Instruction{
Raw: "fold along x=5",
Dir: "left",
Value: 5,
},
},
}
// run each of the test cases, in parallel, as subtests
for name, testCase := range testCases {
tc := testCase // capture for scope
// sub test `tSub` will be run in its own goroutine
t.Run(name, func(tSub *testing.T) {
tSub.Parallel()
i, err := NewInstruction(tc.line)
if err != nil {
tSub.Log("how did this happen?") // prefer to fmt.Println()
tSub.Fatal(err)
}
if i.Raw != tc.ins.Raw {
tSub.Fatalf("expected Raw: %q got: %q\n", tc.ins.Raw, i.Raw)
}
if i.Dir != tc.ins.Dir {
tSub.Fatalf("expected Dir: %q got: %q\n", tc.ins.Dir, i.Dir)
}
if i.Value != tc.ins.Value {
tSub.Fatalf("expected Value: %d got: %d\n", tc.ins.Value, i.Value)
}
})
}
}
WebAssembly
Notes:
- only compiles functions in package main; but those can still call into modules
- specific type conversion rules via js.ValueOf
- .wasm binaries can be very large but may be compressed before being served
GOOS=js GOARCH=wasm go build -o ./main.wasm
Go Terminology
- fmt.Fprint, and others
- file (“F”) print; golang uses io.Reader
- fmt.Sprint, and others
- string (“S”) print
- channel
- typed conduit for sending and receiving values
- closure
- a function value that references variables from outside its body
- default format
- how a value’s type is printed
- format verb
- the specifier, like %v and %T, used to print operands of functions like fmt.Sprintf
- function
- takes zero or more arguments
- goroutine
- a lightweight thread managed by the go runtime
- import path
- a string used to import a package. A package's import path is its module path joined with its subdirectory within the module
- install
- the compilation of code to create a binary executable, and then copying that executable into a directory
- interface
- a set of method signatures; can be thought of as a tuple containing a concrete value and a type
- method
- a function with a receiver argument
- module
- a collection of related Go packages that are released together
- module path
- the import path prefix for all packages within the module
- package
- a collection of source files in the same directory that are compiled together
- pointer
- a pointer holds the memory address of a value
- pointer type / reference type
- a type that contains a pointer to the concrete type
- precision
- for floats, the number of places after the decimal
- slice capacity
- the number of elements in the underlying array, counting from the first item in the slice
- slice length
- the number of elements it contains
- width
- for most values this is the minimum number of runes to output, padding if necessary. refer to the
fmt
package documentation for special cases and more info.
Frequently Asked Questions (FAQ)
What is the difference between a nil slice and an empty slice?
A nil
slice has no pointer to an underlying array. An empty slice has a pointer to an (empty) underlying array. Both nil
and empty slices have a len
and cap
of 0.
Further explanation in answer: The zero value of a slice is not nil
Does a map resize down after deletions?
No, there is ongoing discussion in the GitHub issue “runtime: shrink map as elements are deleted”
Can you initialize a map with a default value?
No built-in way. Instead check presence and set value when absent.
What is the size of Go’s int? What is the width of Go’s int?
Architecture dependent:
- 32 bits on a 32-bit system
- 64 bits on a 64-bit system
What does the “A” stand for in strconv.Atoi() (and strconv.Itoa())?
ASCII
Does Go have a ternary operator?
No, use an if else
conditional. See Why does Go not have the ?:
operator?.
How to print my object as a string?
Implement the Stringer interface.
Does Go have a Set data structure?
No, not built-in and not in the standard library. Sets can be emulated using maps or via third party libraries.
Resources
Note: lists below are not exhaustive.
Installation
Documentation
- Official Documentation
- Frequently Asked Questions (FAQ)
- References
- The Go Programming Language Specification
- The Go Memory Model
- Modules
- standard library (below are selected packages, see here for a full list):
- “x” sub-directories / sub-repositories (full list):
- 3rd-party:
- Tutorials and Learning
- Go Wiki
- Repositories
- The Go programming language canonical repository
- The Go programming language GitHub mirror repository
- The Go Blog: Blog Index, and selected posts:
- (2011 Jan 05) Go Slices: usage and internals
- (2013 Oct 23) Strings, bytes, runes and characters in Go
- (2014 Mar 13) Go Concurrency Patterns: Pipelines and cancellation
- (2015 Feb 04) Package names
- (2016 Oct 03) Using Subtests and Sub-benchmarks
- YouTube
- Other
- Go Module Mirror, Index, and Checksum Database
- sum.golang.org - an auditable checksum database which will be used by the go command to authenticate modules
- proxy.golang.org - a module mirror which implements the module proxy protocol
- index.golang.org - an index which serves a feed of new module versions that become available by proxy.golang.org
Libraries
- google/go-cmp - Package for equality of Go values
- thoas/go-funk - A modern Go utility library which provides helpers (map, find, contains, filter, ...)
go-study
README.md
# go-study
personal study area for the Go programming language
lang/constants.go
package lang
// allowed constant types
const One = 1 // numbers
const A = 'A' // runes
const Hello = "HELLO" // strings
const False = false // bools
// not allowed constant types; must be `var`
var m map[string]int // maps. no const immutable maps
var a [5]int // arrays
var s []int // slices
lang/statements/iteration.go
package statements
import "fmt"
func iterationDemo() {
// for loop with single condition, form 1 (AKA while loop)
sum := 0
for sum < 100 {
sum += 2
}
// for loop with single condition, form 2 (if condition is absent,
// it is equivalent to `true`)
someCondition := true
for {
if someCondition {
someCondition = false
fmt.Println("continuing")
continue
} else {
fmt.Println("breaking out")
break
}
}
// for loop with `for` clause / normal for loop
for i := 0; i < 10; i++ {
sum += i
}
// for loop with `range` clause
// example: ranging over a slice / range over a slice
pow := []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow { // i is index; v is _copy_ of element at i
fmt.Printf("2**%d = %d\n", i, v)
}
// example: ranging over a string / range over string. note: the
// index i may not be what you expect—range moves over Unicode
// code points (runes) and the index is the index in the string's
// underlying array of bytes.
//
// this prints:
//
// 0: 你
// 3: 好
// 6: 世
// 9: 界
for i, rune := range "你好世界" {
fmt.Printf("%d: %c\n", i, rune)
}
// example: ranging over a map / range over map. note: order is not guaranteed!
m := map[string]int{
"foo": 0,
"bar": 1,
}
for key, value := range m {
fmt.Printf("%s: %d\n", key, value)
}
// example: ranging over a channel / range over channel
c := make(chan int)
f := func(c chan int) {
for _, v := range []int{10, 20, 30} {
c <- v
}
close(c)
}
go f(c)
for v := range c {
fmt.Printf("%d\n", v)
}
// for loop emulating do-while loop
var counter int
for ok := true; ok; ok = (counter < 1) {
fmt.Println("we win only once!")
counter++
}
}
lang/statements/switch.go
package statements
import "fmt"
func switchDemo() {
input := "Hello World!"
score := 0
for _, r := range input {
switch r {
case 'a', 'A':
fallthrough // required to fall through
case 'e', 'E':
fallthrough
case 'i', 'I':
fallthrough
case 'o', 'O':
fallthrough
case 'u', 'U':
score += 10
// does not fall through
case '!':
score += 10
// does not fall through
default:
score -= 1
}
}
fmt.Println(score)
}
lang/types/basic_types.go
package types
// bool zero value. boolean zero value
var b bool // false
// uninitialized string. string zero value
var str string // ""
// int zero value
var i int // 0
var i8 int8
var i16 int16
var i32 int32
var i64 int64
var ui uint
var ui8 uint8
var ui16 uint16
var ui32 uint32
var ui64 uint64
var uiptr uintptr
var by byte // alias for uint8
var r rune // alias for uint32; represents unicode code point
var f32 float32
var f64 float64
var c64 complex64
var c128 complex128
lang/types/map.go
package types
import "fmt"
func mapDemo() {
// uninitialized map. map zero value. an uninitialized map cannot be added to
var m map[string]int // nil. key type is string, value type is int
// map literal. map init. empty map
m = map[string]int{}
// make map. map init
m = make(map[string]int)
// make map with initial space for approximately 5 elements. map init
m = make(map[string]int, 5)
// map set key value. map insert. map update
m["1"] = 1
m["2"] = 2
m["3"] = 3
m["4"] = 4
m["5"] = 5
m["6"] = 6 // map automatically grows to accommodate
// map delete key
delete(m, "6")
// map get value. if not present, will be value type's zero value
maybeElem := m["6"]
// map check if key exists. maybeElem will still be the value type's zero
// value if not found
maybeElem, ok := m["6"]
if ok {
// key was found in our map
}
// map check if key exists
_, ok = m["6"]
if ok {
// key was found in our map
}
// combined syntax
if maybeElem, ok = m["6"]; ok {
// key was found in our map
} else {
// key was not found in our map
}
// common syntax. val only exists in scope of the conditional
if val, ok := m["6"]; ok {
// do something with val
fmt.Println(val)
} else {
// do something having not found it
}
// common syntax. you need to use val
val, ok := m["6"]
if !ok {
// set val to a default
val = -1
}
// map size. map length. size of map
if 0 < len(m) {
// take some action
}
// map copy. copy map. map copy keys and values. alternatively: use `maps.Copy`
m2 := map[string]int{}
for k, v := range m {
m2[k] = v
}
fmt.Println(m, maybeElem, val, m2)
}
lang/types/slice.go
package types
import "fmt"
func sliceDemo() {
// uninitialized slice. slice zero value
var s []int // nil
// the zero value can have elements appended. slice append. append slice.
s = append(s, 0) // append 0 to s, assigning it to s
// slice literal. slice init. empty slice
s = []int{}
// make slice with initial size 10. slice init
s = make([]int, 10)
// slice append. slice concat
s1 := []int{0, 1, 2}
s2 := []int{3, 4, 5}
s3 := append(s1, s2...) // append the contents of s2 to s1
fmt.Println(s3) // [0 1 2 3 4 5]
// slice get first value
first := s3[0]
// slice get last value
last := s3[len(s3)-1]
// slice remove first value. slice remove first element.
s3 = s3[1:]
// slice remove last value. slice remove last element
s3 = s3[:len(s3)-1]
fmt.Println(first, last, s3)
// slice fill with -1
s = make([]int, 10)
for i := range s {
s[i] = -1
}
}
lang/types/string.go
package types
import "fmt"
func stringDemo() {
// string literal. string init
str := "hello world"
// multiline string. multi-line string. multi line string
str = `use
backticks
for a multi-line string`
str = "or use\nnewline characters\n"
// cannot escape backticks
str = `no way
to escape backticks,
but you can ` + `do
this`
fmt.Println(str)
}
lang/variables/swap.go
package variables
func Swap() {
// swap two variables
a, b := 0, 10
b, a = a, b
}
personal_conventions.go
package main
// prefer underscore case for filenames; e.g. `personal_convention.go` to `personal-convention.go` or `personalconvention.go``
type PersonalConventions struct {
}
// prefer upper camel case for constant names
// prefer `Id` to `ID`
const BazId = "90210"
func foo() {
// prefer single assignment (one assignment per line) over parallel
// assignment (`fooBar1, fooBar2 := "hello ", "world"`)
fooBar1 := "hello "
fooBar2 := "world"
// prefer lower camel case for variable names
x := 10
for i := 0; i < 10; i++ {
// prefer newly named variables and avoid shadowing where not necessary
// (e.g. do not use `x := i` here)
y := i
}
}
stdlib/errors_demo/errors.go
package errors_demo
import (
"errors"
"fmt"
"os"
)
func errorsDemo() {
// create new error. make new error. make error. create error.
err := errors.New("I am an error!")
// check error type
if errors.Is(err, os.ErrClosed) {
fmt.Println("huh?")
}
}
stdlib/fmt_demo/fmt.go
package fmt_demo
import (
"fmt"
"os"
)
func fmtDemo() {
// fmt.Sprint: short for "string print"
// spaces added automatically for consecutive non-strings. manual spaces
// required for strings.
// concatenate strings
// concat strings
// string concat
// append strings
// string append
s := fmt.Sprint(3, 2, 1, " hello", " world!\n")
fmt.Printf(s)
s = fmt.Sprintf("format verbs work as expected: %d + %d = %d\n", 3, 5, 3+5)
fmt.Printf(s)
// spaces and trailing newline automatically added for Sprintln
s = fmt.Sprintln("hello", "world!")
fmt.Printf(s)
// fmt.Print: short for "print"
// convention: no error check
// spaces added automatically for consecutive non-strings. manual spaces
// required for strings.
fmt.Print(3, 2, 1, " hello", " world!\n")
fmt.Printf("format verbs work as expected: %d + %d = %d\n", 3, 5, 3+5)
// spaces and trailing newline automatically added for Println
fmt.Println("hello", "world!")
// fmt.Fprint: short for "file print"
// spaces added automatically for consecutive non-strings. manual spaces
// required for strings.
fmt.Fprint(os.Stdout, 2, 1, " hello", " world!\n")
fmt.Fprintf(os.Stdout, "format verbs work as expected: %d + %d = %d\n", 3, 5, 3+5)
// spaces and trailing newline automatically added for Fprintln
fmt.Fprintln(os.Stdout, "hello", "world!")
// double quotes
doubleQ := `"we win!"`
s = fmt.Sprintf("%s", doubleQ)
fmt.Println(s) // "we win!"
s = fmt.Sprintf("%q", doubleQ)
fmt.Println(s) // "\"we win!\""
// gotcha: the number of runes to express the number includes the `.` character
// width is the minimum number of runes to output. float width, floating
// point width, printing floats.
val := 123.456
s = fmt.Sprintf("%f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%1f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%2f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%3f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%4f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%5f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%6f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%7f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%8f", val)
fmt.Println(s) // 123.456000
// precision is the amount of runes after the decimal place. float precision,
// floating point precision. printing floats.
s = fmt.Sprintf("%f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%.f", val)
fmt.Println(s) // 123
s = fmt.Sprintf("%.1f", val)
fmt.Println(s) // 123.5
s = fmt.Sprintf("%.2f", val)
fmt.Println(s) // 123.46
s = fmt.Sprintf("%.3f", val)
fmt.Println(s) // 123.456
s = fmt.Sprintf("%.4f", val)
fmt.Println(s) // 123.4560
s = fmt.Sprintf("%.5f", val)
fmt.Println(s) // 123.45600
s = fmt.Sprintf("%.6f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%.7f", val)
fmt.Println(s) // 123.4560000
s = fmt.Sprintf("%.8f", val)
fmt.Println(s) // 123.45600000
// width and precision can be combined, with any excess padded with spaces by
// default
s = fmt.Sprintf("%f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%12.f", val)
fmt.Println(s) // 123
s = fmt.Sprintf("%12.1f", val)
fmt.Println(s) // 123.5
s = fmt.Sprintf("%12.2f", val)
fmt.Println(s) // 123.46
s = fmt.Sprintf("%12.3f", val)
fmt.Println(s) // 123.456
s = fmt.Sprintf("%12.4f", val)
fmt.Println(s) // 123.4560
s = fmt.Sprintf("%12.5f", val)
fmt.Println(s) // 123.45600
s = fmt.Sprintf("%12.6f", val)
fmt.Println(s) // 123.456000
s = fmt.Sprintf("%12.7f", val)
fmt.Println(s) // 123.4560000
s = fmt.Sprintf("%12.8f", val)
fmt.Println(s) // 123.45600000
// excess can also be zero padded. zero-padded. zero padding
s = fmt.Sprintf("%08.2f", val)
fmt.Println(s) // 00123.46
}
stdlib/fmt_demo/formatting_verbs.go
package fmt_demo
import "fmt"
func formattingVerbsDemo() {
// formatting verbs of note
v := struct{ x int }{x: 1}
// literal percent sign.
fmt.Printf("%% \n") // %
// value in default format.
fmt.Printf("%v \n", v) // {1}
// value in default format, with field names
fmt.Printf("%+v \n", v) // {x:1}
// value in Go-syntax
fmt.Printf("%#v \n", v) // struct { x int }{x:1}
// the uninterpreted bytes of a string
fmt.Printf("%s \n", "foo") // foo
// boolean: the word `true` or `false`
fmt.Printf("%t \n", true) // true
// a double-quoted, and safely escaped, string
fmt.Printf("%q \n", `"foo"`) // "\"foo\""
}
stdlib/log_demo/log.go
package log_demo
import "log"
func logDemo() {
log.Printf("hello %s\n", "world")
log.Println("hello world")
}
stdlib/os_demo/os.go
package os_demo
import (
"errors"
"fmt"
"log"
"os"
)
func osDemo() {
// create a file. write to a file. does nothing if it exists due to `os.O_EXCL`
f, err := os.OpenFile("path/to/file.md", os.O_RDWR|os.O_CREATE|os.O_EXCL, 0755)
defer f.Close()
if err != nil {
if errors.Is(err, os.ErrExist) {
log.Printf("could not create file. skipping. message: %v\n", err)
} else {
log.Fatalf("could not create file. message: %v\n", err)
}
} else {
fmt.Fprintln(f, "some text!")
}
}
stdlib/sort_demo/sort.go
package sort_demo
import (
"sort"
)
func sortDemo() {
fruit := []string{"durian", "canteloupe", "apple", "banana"}
// sort strings in place. sort string slice
sort.Strings(fruit) // ascending
sort.Sort(sort.Reverse(sort.StringSlice(fruit))) // descending
// note: sort.StringSlice attaches the methods of Interface to []string,
// sorting in increasing order.
counts := []int{3, 5, 4, 2, 1}
// sort ints in place. sort int slice
sort.Ints(counts) // ascending
sort.Sort(sort.Reverse(sort.IntSlice(counts))) // descending
// note: `sort.IntSlice` attaches the methods of Interface to []int, sorting
// in increasing order. `sort.Reverse` just tweaks that to call `Less(i, j)`
// as `Less(j, i)`
// sort structs in place. sort struct slice
type coord struct {
x int
y int
}
coords := []coord{{3, 2}, {1, 2}, {1, 1}}
sort.Slice(coords, func(a int, b int) bool {
if coords[a].y == coords[b].y {
return coords[a].x < coords[b].x
}
return coords[a].y < coords[b].y
})
}
stdlib/strconv_demo/strconv.go
package strconv_demo
import (
"fmt"
"log"
"strconv"
)
func main() {
// string convert ascii to integer. convert string to integer.
i, err := strconv.Atoi("1")
if err != nil {
log.Fatal(err)
}
fmt.Println(i) // 1
}
stdlib/strings_demo/strings.go
package strings_demo
import (
"log"
"strings"
)
// use this package when manipulating UTF-8 strings
func stringsDemo() {
// split string on whitespace
fruits1 := strings.Fields("apple banana cantaloupe")
log.Println(fruits1)
// split string on delimiter
fruits2 := strings.Split("apple,banana,cantaloupe", ",")
log.Println(fruits2)
}
stdlib/unicode_demo/unicode.go
package unicode_demo
import (
"unicode"
)
func unicodeDemo() {
// report bool if rune is lower case
unicode.IsLower('r')
// report bool if rune is upper case
unicode.IsUpper('r')
}
tricks/bit_shifting_tricks.go
package tricks
// bit shifting: shift the binary representation of `1` `20` bits to the left. equivalent to 1 * 2^20
const OneMB = 1 << 20 // 1 MB
tricks/math_tricks.go
package tricks
import (
"fmt"
"math"
)
func demoMathTricks() {
a := 10
b := 3
// integer floor. int floor
floor := a / b
// integer ceiling. int ceiling
ceil := int(math.Ceil(float64(a) / float64(b)))
fmt.Println(floor, ceil)
}
tricks/slice_tricks.go
package tricks
// make a range from low to high, 0 to num
func makeRange(low, high int) []int {
var r []int
for i := low; i < high+1; i++ {
r = append(r, i)
}
return r
}
// get minimum of slice. minimum from slice. no built-in
func getMin(input []int) int {
var min int
// note: be aware of how this behaves with the empty slice
for i, v := range input {
if i == 0 || v < min {
min = v
}
}
return min
}
x/exp/maps/maps.go
package maps
import (
"fmt"
"golang.org/x/exp/maps"
)
func demoMaps() {
m1 := make(map[string]*int)
count := 0
m1["count"] = &count
// map clone. this is a shallow copy. note the behavior when we change a
// value that is a reference type
m2 := maps.Clone(m1)
*m1["count"]++
fmt.Println(m1)
fmt.Println(m2)
// map copy. copy map.
maps.Copy(m2, m1)
*m1["count"]++
fmt.Println(m1)
fmt.Println(m2)
}
x/exp/slices/slices.go
package slices
import "golang.org/x/exp/slices"
func demoSlices() {
items := []string{"a", "b", "c"}
// slice contains. slice includes
slices.Contains(items, "a") // true
slices.Contains(items, "d") // false
}