When your main file (that belongs to package main and have a main function) has the following relative path : /my/program/main.go. Open a terminal and type
\n$ go build -o binaryName /my/program/main.go
\nThe program will be compiled. A binary named binaryName will be created in the current directory (where you execute the command)
\n\nA growable collection of elements of the same type.
Size is not known at compile time
Internally: a pointer to an underlying array
A good resource for playing with slices is the “Slice Tricks” page1
make([]int,0)
: a slice of integers with a length 0 and a capacity of 0
make([]int,0,10)
: a slice of integers with a length 0 and a capacity of 10
Slicing an existing array :
a := [4]int{1,2,3,4}\ns = a[:3]\n// s = [1,2]\n// capacity = 4\n// length = 2
\ns := []int{1,2,3,4}
create a slice and fill it directly
s = append(s,0)
: Add 0 to the slice s
s[8]
\nget the element of slice s at index 8. (be careful, the index starts at 0)
\n\nfunc copy(destination, source []Type) int
\na := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}\na = a[:0]\n\n// OR\n\na = nil
\n\nb := []int{2, 3, 4}\nb = append([]int{1}, b...)
\n\na = append(a[:i], a[i+1:]...)
\n\nYou will have to iterate over it (with a for loop). Maybe use a map instead?
\n\ns = append(s, 0)\ncopy(s[i+1:], s[i:])\ns[i] = x
\n\nInitialize Go modules
\n$ go mod init yourModulePath
\nUpgrade all dependencies to the latest version (minor versions and patches)
\n$ go get -u
Upgrade a specific dependency (ex: gitlab.com/loir402/foo)
\n$ go get gitlab.com/loir402/foo
Upgrade/Downgrade a specific dependency to a specific revision
\n$ $ go get module_path@X
\nWhere X can be :
\nA commit hash
\nA version string
\nCleanup your go.mod and go.sum file
\n$ go mod tidy
Print the dependency graph of your module
\n$ go mod graph
Create a vendor directory to store all your dependencies
\n$ go mod vendor
Check that the dependencies downloaded locally have not been altered
\n$ go mod verify
List all dependencies along with their version
\n$ go list -m all
goimports
is a command-line tool to automatically sort the imports of a source file : Here is an example of unsorted import declarations
//...\nimport (\n "encoding/csv"\n "fmt"\n "log"\n "math/rand"\n "maximilien-andile.com/errors/application/generator"\n "os"\n "time"\n)\n//...
\nHere is the sorted version :
\nimport (\n "encoding/csv"\n "fmt"\n "log"\n "math/rand"\n "os"\n "time"\n\n "maximilien-andile.com/errors/application/generator"\n)
\n\nOpen a terminal and type the following command :
\n$ go get golang.org/x/tools/cmd/goimports
\nThe binary will be installed here : $GOPATH/bin/goimports
.
To make it available everywhere, make sure to add the folder $GOPATH/bin
to your PATH
The command to use is :
\n$ goimports -w file.go
\nWhere file.go
is the file that you want to treat
Tests files are placed in the package directory
They have the _test.go suffix
Test functions are exported and have a specific name
\nHere is an example table test :
\nfunc Test_totalPrice(t *testing.T) {\n type parameters struct {\n nights uint\n rate uint\n cityTax uint\n }\n type testCase struct {\n name string\n args parameters\n want uint\n }\n tests := []testCase{\n {\n name: "test 0 nights",\n args: parameters{nights: 0, rate: 150, cityTax: 12},\n want: 0,\n },\n {\n name: "test 1 nights",\n args: parameters{nights: 1, rate: 100, cityTax: 12},\n want: 112,\n },\n {\n name: "test 2 nights",\n args: parameters{nights: 2, rate: 100, cityTax: 12},\n want: 224,\n },\n }\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n time.Sleep(time.Second*1)\n t.Parallel()\n if got := totalPrice(tt.args.nights, tt.args.rate, tt.args.cityTax); got != tt.want {\n t.Errorf("totalPrice() = %v, want %v", got, tt.want)\n }\n })\n }\n}
\n\nRun all tests in a project
\n$ go test ./...
Run tests of a specific package
\nInto the package directory :
\n$ go test
Outside the package directory :
\n$ go test modulepath/packagename
The module path is generally an URL pointing to a code-sharing website.
\nEx : gitlab.com/loir402/bluesodium
The module path is written on the go.mod file :
\nmodule gitlab.com/loir402/bluesodium\n\ngo 1.15
\nOthers will use the module path to import your module (if you have access to the repository) via, for instance, the go get command
\ngo get gitlab.com/loir402/bluesodium
\nThe last part of the URL should match the name of the principal package of your module (that will generally be placed at the root of the project directory).
\npackage main\n\nimport "gitlab.com/loir402/bluesodium"\n\nfunc main() {\n bluesodium.Color()\n}
\n\nshort
simple
concise
one word is better than two or more
Here is the definition of the error
interface (in the standard library) :
package builtin\n//...\ntype error interface {\n Error() string\n}
\nHere is an example implementation of this interface :
\n// ReadingError is a custom type\ntype ReadingError struct {\n}\n\n// ReadingError implments error interface\nfunc (e *ReadingError) Error() string {\n return "error"\n}
\n\nHere is the syntax of a type assertion.
\nx.(T)
\nx
has a type interfaceT
is a type. It might be a concrete type or a type interface.
func doSomething() error {\n //...\n}\n\nerr := doSomething()
\nIn this program, we define a function doSomething
which returns an element of type interface error
. We execute this function, and we assign the return value to a new variableerr
.
We just know that err
is of type interface error
. We want to check that the dynamic type of err
is *ReadingError
. We can use a type assertion :
// type assertion\nv, ok := err.(*ReadingError)\n\nif ok {\n fmt.Println("err is of type *ReadingError")\n}
\nerr.(*ReadingError)
returns two values :
When err is of type *ReadingError
. Assertion holds
v
is of type *ReadingError
ok
is equal to true2
Otherwise
\nv
is the zero value of the type *ReadingError
. In this context, it’s equal to nil
.
ok
is equal to false3
The type assertion err.(*ReadingError)
is legal in this context. The type *ReadingError
implements the interface error
and the value err
is of interface type error
.
T
is an interface type Let’s take an example with two interfaces Adder
and Divider
:
type Adder interface {\n Add(a, b int) int\n}\n\ntype Divider interface {\n Divide(a, b int) float64\n}
\nThen we define a new type MyAdder which implements Adder
and Divider
.
type MyAdder struct {\n}\n\nfunc (t *MyAdder) Add(a, b int) int {\n return a + b\n}\nfunc (t *MyAdder) Divide(a, b int) float64 {\n return float64(a / b)\n}
\nThe function foo
returns an Adder
interface type.
func foo() Adder {\n return &MyAdder{}\n}
\nLet’s check if the return value of foo
also implements the Divider
interface :
func main() {\n x := foo()\n if v, ok := x.(Divider); ok {\n fmt.Println("x implements also interface Divider",v)\n }\n}
\nThe syntax is identical. The type assertion will also check if x
is not nil
.
When x
implements Divider
and is not nil :
v
implements Divider
ok
is equal to true
Otherwise
\nv
is equal to nil
ok
is equal to false
When you use the syntax :
\nv, ok := x.(Divider)
\nyour program will not panic if x
is not of type Divider
. Whereas the following syntax might cause a panic :
v := x.(Multiplier)\nfmt.Printf("%v", v)
\nHere is the standard output :
\npanic: interface conversion: *main.MyAdder is not main.Multiplier: missing method Multiply\n\ngoroutine 1 [running]:\nmain.main()\n /path/to/main.go:38 +0x100\n\nProcess finished with exit code 2
\n\nTo check if an environment variable exists, you can use the os
package :
port, found := os.LookupEnv("DB_PORT")\nif !found {\n log.Fatal("impossible to start up, DB_PORT env var is mandatory")\n}
\nLookupEnv allows you to check if an env exists before using it.
\n\nPrevious
\n\t\t\t\t\t\t\t\t\tDesign Recommendations
\n\t\t\t\t\t\t\t\t