688 lines
10 KiB
Markdown
688 lines
10 KiB
Markdown
---
|
|
title: Go
|
|
prism_languages: [go, bash]
|
|
weight: -3
|
|
tags: [Featured]
|
|
category: C-like
|
|
updated: 2020-06-21
|
|
---
|
|
|
|
## Getting started
|
|
{: .-three-column}
|
|
|
|
### Introduction
|
|
{: .-intro}
|
|
|
|
- [A tour of Go](https://tour.golang.org/welcome/1) _(tour.golang.org)_
|
|
- [Go repl](https://repl.it/languages/go) _(repl.it)_
|
|
- [Golang wiki](https://go.dev/wiki/) _(go.dev)_
|
|
|
|
### Hello world
|
|
{: .-prime}
|
|
|
|
#### hello.go
|
|
{: .-file}
|
|
|
|
```go
|
|
package main
|
|
|
|
import "fmt"
|
|
|
|
func main() {
|
|
message := greetMe("world")
|
|
fmt.Println(message)
|
|
}
|
|
|
|
func greetMe(name string) string {
|
|
return "Hello, " + name + "!"
|
|
}
|
|
```
|
|
|
|
```bash
|
|
$ go build
|
|
```
|
|
|
|
Or try it out in the [Go repl](https://repl.it/languages/go), or [A Tour of Go](https://tour.golang.org/welcome/1).
|
|
|
|
### Variables
|
|
|
|
#### Variable declaration
|
|
|
|
```go
|
|
var msg string
|
|
var msg = "Hello, world!"
|
|
var msg string = "Hello, world!"
|
|
var x, y int
|
|
var x, y int = 1, 2
|
|
var x, msg = 1, "Hello, world!"
|
|
msg = "Hello"
|
|
```
|
|
|
|
#### Declaration list
|
|
|
|
``` go
|
|
var (
|
|
x int
|
|
y = 20
|
|
z int = 30
|
|
d, e = 40, "Hello"
|
|
f, g string
|
|
)
|
|
```
|
|
|
|
#### Shortcut of above (Infers type)
|
|
|
|
```go
|
|
msg := "Hello"
|
|
x, msg := 1, "Hello"
|
|
```
|
|
|
|
### Constants
|
|
|
|
```go
|
|
const Phi = 1.618
|
|
const Size int64 = 1024
|
|
const x, y = 1, 2
|
|
const (
|
|
Pi = 3.14
|
|
E = 2.718
|
|
)
|
|
const (
|
|
Sunday = iota
|
|
Monday
|
|
Tuesday
|
|
Wednesday
|
|
Thursday
|
|
Friday
|
|
Saturday
|
|
)
|
|
```
|
|
|
|
Constants can be character, string, boolean, or numeric values.
|
|
|
|
See: [Constants](https://tour.golang.org/basics/15)
|
|
|
|
## Basic types
|
|
{: .-three-column}
|
|
|
|
### Strings
|
|
|
|
```go
|
|
str := "Hello"
|
|
```
|
|
|
|
```go
|
|
str := `Multiline
|
|
string`
|
|
```
|
|
|
|
Strings are of type `string`.
|
|
|
|
### Numbers
|
|
|
|
#### Typical types
|
|
|
|
```go
|
|
num := 3 // int
|
|
num := 3. // float64
|
|
num := 3 + 4i // complex128
|
|
num := byte('a') // byte (alias for uint8)
|
|
```
|
|
|
|
#### Other types
|
|
|
|
```go
|
|
var u uint = 7 // uint (unsigned)
|
|
var p float32 = 22.7 // 32-bit float
|
|
```
|
|
|
|
### Arrays
|
|
|
|
```go
|
|
// var numbers [5]int
|
|
numbers := [...]int{0, 0, 0, 0, 0}
|
|
```
|
|
|
|
Arrays have a fixed size.
|
|
|
|
### Slices
|
|
|
|
```go
|
|
slice := []int{2, 3, 4}
|
|
```
|
|
|
|
```go
|
|
slice := []byte("Hello")
|
|
```
|
|
|
|
Slices have a dynamic size, unlike arrays.
|
|
|
|
### Pointers
|
|
|
|
```go
|
|
func main () {
|
|
b := *getPointer()
|
|
fmt.Println("Value is", b)
|
|
}
|
|
```
|
|
{: data-line="2"}
|
|
|
|
```go
|
|
func getPointer () (myPointer *int) {
|
|
a := 234
|
|
return &a
|
|
}
|
|
```
|
|
{: data-line="3"}
|
|
|
|
```go
|
|
a := new(int)
|
|
*a = 234
|
|
```
|
|
{: data-line="2"}
|
|
|
|
Pointers point to a memory location of a variable. Go is fully garbage-collected.
|
|
|
|
See: [Pointers](https://tour.golang.org/moretypes/1)
|
|
|
|
### Type conversions
|
|
|
|
```go
|
|
i := 2
|
|
f := float64(i)
|
|
u := uint(i)
|
|
```
|
|
|
|
See: [Type conversions](https://tour.golang.org/basics/13)
|
|
|
|
## Flow control
|
|
{: .-three-column}
|
|
|
|
### Conditional
|
|
|
|
```go
|
|
if day == "sunday" || day == "saturday" {
|
|
rest()
|
|
} else if day == "monday" && isTired() {
|
|
groan()
|
|
} else {
|
|
work()
|
|
}
|
|
```
|
|
{: data-line="1,3,5"}
|
|
|
|
See: [If](https://tour.golang.org/flowcontrol/5)
|
|
|
|
### Statements in if
|
|
|
|
```go
|
|
if _, err := doThing(); err != nil {
|
|
fmt.Println("Uh oh")
|
|
}
|
|
```
|
|
{: data-line="1"}
|
|
|
|
A condition in an `if` statement can be preceded with a statement before a `;`. Variables declared by the statement are only in scope until the end of the `if`.
|
|
|
|
See: [If with a short statement](https://tour.golang.org/flowcontrol/6)
|
|
|
|
### Switch
|
|
|
|
```go
|
|
switch day {
|
|
case "sunday":
|
|
// cases don't "fall through" by default!
|
|
fallthrough
|
|
|
|
case "saturday":
|
|
rest()
|
|
|
|
default:
|
|
work()
|
|
}
|
|
```
|
|
|
|
See: [Switch](https://github.com/golang/go/wiki/Switch)
|
|
|
|
### For loop
|
|
|
|
```go
|
|
for count := 0; count <= 10; count++ {
|
|
fmt.Println("My counter is at", count)
|
|
}
|
|
```
|
|
|
|
See: [For loops](https://tour.golang.org/flowcontrol/1)
|
|
|
|
### For-Range loop
|
|
|
|
```go
|
|
entry := []string{"Jack","John","Jones"}
|
|
for i, val := range entry {
|
|
fmt.Printf("At position %d, the character %s is present\n", i, val)
|
|
}
|
|
```
|
|
|
|
See: [For-Range loops](https://gobyexample.com/range)
|
|
|
|
### While loop
|
|
|
|
```go
|
|
n := 0
|
|
x := 42
|
|
for n != x {
|
|
n := guess()
|
|
}
|
|
```
|
|
|
|
See: [Go's "while"](https://tour.golang.org/flowcontrol/3)
|
|
|
|
## Functions
|
|
{: .-three-column}
|
|
|
|
### Lambdas
|
|
|
|
```go
|
|
myfunc := func() bool {
|
|
return x > 10000
|
|
}
|
|
```
|
|
{: data-line="1"}
|
|
|
|
Functions are first class objects.
|
|
|
|
### Multiple return types
|
|
|
|
```go
|
|
a, b := getMessage()
|
|
```
|
|
|
|
```go
|
|
func getMessage() (a string, b string) {
|
|
return "Hello", "World"
|
|
}
|
|
```
|
|
{: data-line="2"}
|
|
|
|
|
|
### Named return values
|
|
|
|
```go
|
|
func split(sum int) (x, y int) {
|
|
x = sum * 4 / 9
|
|
y = sum - x
|
|
return
|
|
}
|
|
```
|
|
{: data-line="4"}
|
|
|
|
By defining the return value names in the signature, a `return` (no args) will return variables with those names.
|
|
|
|
See: [Named return values](https://tour.golang.org/basics/7)
|
|
|
|
## Packages
|
|
{: .-three-column}
|
|
|
|
### Importing
|
|
|
|
```go
|
|
import "fmt"
|
|
import "math/rand"
|
|
```
|
|
|
|
```go
|
|
import (
|
|
"fmt" // gives fmt.Println
|
|
"math/rand" // gives rand.Intn
|
|
)
|
|
```
|
|
|
|
Both are the same.
|
|
|
|
See: [Importing](https://tour.golang.org/basics/1)
|
|
|
|
### Aliases
|
|
|
|
```go
|
|
import r "math/rand"
|
|
```
|
|
{: data-line="1"}
|
|
|
|
```go
|
|
r.Intn()
|
|
```
|
|
|
|
### Exporting names
|
|
|
|
```go
|
|
func Hello () {
|
|
···
|
|
}
|
|
```
|
|
|
|
Exported names begin with capital letters.
|
|
|
|
See: [Exported names](https://tour.golang.org/basics/3)
|
|
|
|
### Packages
|
|
|
|
```go
|
|
package hello
|
|
```
|
|
|
|
Every package file has to start with `package`.
|
|
|
|
## Concurrency
|
|
{: .-three-column}
|
|
|
|
### Goroutines
|
|
|
|
```go
|
|
func main() {
|
|
// A "channel"
|
|
ch := make(chan string)
|
|
|
|
// Start concurrent routines
|
|
go push("Moe", ch)
|
|
go push("Larry", ch)
|
|
go push("Curly", ch)
|
|
|
|
// Read 3 results
|
|
// (Since our goroutines are concurrent,
|
|
// the order isn't guaranteed!)
|
|
fmt.Println(<-ch, <-ch, <-ch)
|
|
}
|
|
```
|
|
{: data-line="3,6,7,8,13"}
|
|
|
|
```go
|
|
func push(name string, ch chan string) {
|
|
msg := "Hey, " + name
|
|
ch <- msg
|
|
}
|
|
```
|
|
{: data-line="3"}
|
|
|
|
Channels are concurrency-safe communication objects, used in goroutines.
|
|
|
|
See: [Goroutines](https://tour.golang.org/concurrency/1), [Channels](https://tour.golang.org/concurrency/2)
|
|
|
|
### Buffered channels
|
|
|
|
```go
|
|
ch := make(chan int, 2)
|
|
ch <- 1
|
|
ch <- 2
|
|
ch <- 3
|
|
// fatal error:
|
|
// all goroutines are asleep - deadlock!
|
|
```
|
|
{: data-line="1"}
|
|
|
|
Buffered channels limit the amount of messages it can keep.
|
|
|
|
See: [Buffered channels](https://tour.golang.org/concurrency/3)
|
|
|
|
### Closing channels
|
|
|
|
#### Closes a channel
|
|
|
|
```go
|
|
ch <- 1
|
|
ch <- 2
|
|
ch <- 3
|
|
close(ch)
|
|
```
|
|
{: data-line="4"}
|
|
|
|
#### Iterates across a channel until its closed
|
|
|
|
```go
|
|
for i := range ch {
|
|
···
|
|
}
|
|
```
|
|
{: data-line="1"}
|
|
|
|
#### Closed if `ok == false`
|
|
|
|
```go
|
|
v, ok := <- ch
|
|
```
|
|
|
|
See: [Range and close](https://tour.golang.org/concurrency/4)
|
|
|
|
### WaitGroup
|
|
|
|
```go
|
|
import "sync"
|
|
|
|
func main() {
|
|
var wg sync.WaitGroup
|
|
|
|
for _, item := range itemList {
|
|
// Increment WaitGroup Counter
|
|
wg.Add(1)
|
|
go doOperation(&wg, item)
|
|
}
|
|
// Wait for goroutines to finish
|
|
wg.Wait()
|
|
|
|
}
|
|
```
|
|
{: data-line="1,4,8,12"}
|
|
|
|
```go
|
|
func doOperation(wg *sync.WaitGroup, item string) {
|
|
defer wg.Done()
|
|
// do operation on item
|
|
// ...
|
|
}
|
|
```
|
|
{: data-line="2"}
|
|
|
|
A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. The goroutine calls `wg.Done()` when it finishes.
|
|
See: [WaitGroup](https://golang.org/pkg/sync/#WaitGroup)
|
|
|
|
|
|
## Error control
|
|
|
|
### Defer
|
|
|
|
```go
|
|
func main() {
|
|
defer fmt.Println("Done")
|
|
fmt.Println("Working...")
|
|
}
|
|
```
|
|
{: data-line="2"}
|
|
|
|
Defers running a function until the surrounding function returns.
|
|
The arguments are evaluated immediately, but the function call is not ran until later.
|
|
|
|
See: [Defer, panic and recover](https://blog.golang.org/defer-panic-and-recover)
|
|
|
|
### Deferring functions
|
|
|
|
```go
|
|
func main() {
|
|
defer func() {
|
|
fmt.Println("Done")
|
|
}()
|
|
fmt.Println("Working...")
|
|
}
|
|
```
|
|
{: data-line="2,3,4"}
|
|
|
|
Lambdas are better suited for defer blocks.
|
|
|
|
```go
|
|
func main() {
|
|
var d = int64(0)
|
|
defer func(d *int64) {
|
|
fmt.Printf("& %v Unix Sec\n", *d)
|
|
}(&d)
|
|
fmt.Print("Done ")
|
|
d = time.Now().Unix()
|
|
}
|
|
```
|
|
{: data-line="3,4,5"}
|
|
The defer func uses current value of d, unless we use a pointer to get final value at end of main.
|
|
|
|
## Structs
|
|
{: .-three-column}
|
|
|
|
### Defining
|
|
|
|
```go
|
|
type Vertex struct {
|
|
X int
|
|
Y int
|
|
}
|
|
```
|
|
{: data-line="1,2,3,4"}
|
|
|
|
```go
|
|
func main() {
|
|
v := Vertex{1, 2}
|
|
v.X = 4
|
|
fmt.Println(v.X, v.Y)
|
|
}
|
|
```
|
|
|
|
See: [Structs](https://tour.golang.org/moretypes/2)
|
|
|
|
### Literals
|
|
|
|
```go
|
|
v := Vertex{X: 1, Y: 2}
|
|
```
|
|
|
|
```go
|
|
// Field names can be omitted
|
|
v := Vertex{1, 2}
|
|
```
|
|
|
|
```go
|
|
// Y is implicit
|
|
v := Vertex{X: 1}
|
|
```
|
|
|
|
You can also put field names.
|
|
|
|
### Pointers to structs
|
|
|
|
```go
|
|
v := &Vertex{1, 2}
|
|
v.X = 2
|
|
```
|
|
|
|
Doing `v.X` is the same as doing `(*v).X`, when `v` is a pointer.
|
|
|
|
## Methods
|
|
|
|
### Receivers
|
|
|
|
```go
|
|
type Vertex struct {
|
|
X, Y float64
|
|
}
|
|
```
|
|
|
|
```go
|
|
func (v Vertex) Abs() float64 {
|
|
return math.Sqrt(v.X * v.X + v.Y * v.Y)
|
|
}
|
|
```
|
|
{: data-line="1"}
|
|
|
|
```go
|
|
v := Vertex{1, 2}
|
|
v.Abs()
|
|
```
|
|
|
|
There are no classes, but you can define functions with _receivers_.
|
|
|
|
See: [Methods](https://tour.golang.org/methods/1)
|
|
|
|
### Mutation
|
|
|
|
```go
|
|
func (v *Vertex) Scale(f float64) {
|
|
v.X = v.X * f
|
|
v.Y = v.Y * f
|
|
}
|
|
```
|
|
{: data-line="1"}
|
|
|
|
```go
|
|
v := Vertex{6, 12}
|
|
v.Scale(0.5)
|
|
// `v` is updated
|
|
```
|
|
|
|
By defining your receiver as a pointer (`*Vertex`), you can do mutations.
|
|
|
|
See: [Pointer receivers](https://tour.golang.org/methods/4)
|
|
|
|
## Interfaces
|
|
|
|
### A basic interface
|
|
|
|
```go
|
|
type Shape interface {
|
|
Area() float64
|
|
Perimeter() float64
|
|
}
|
|
```
|
|
|
|
### Struct
|
|
|
|
```go
|
|
type Rectangle struct {
|
|
Length, Width float64
|
|
}
|
|
```
|
|
|
|
Struct `Rectangle` implicitly implements interface `Shape` by implementing all of its methods.
|
|
|
|
### Methods
|
|
|
|
```go
|
|
func (r Rectangle) Area() float64 {
|
|
return r.Length * r.Width
|
|
}
|
|
|
|
func (r Rectangle) Perimeter() float64 {
|
|
return 2 * (r.Length + r.Width)
|
|
}
|
|
```
|
|
|
|
The methods defined in `Shape` are implemented in `Rectangle`.
|
|
|
|
### Interface example
|
|
|
|
```go
|
|
func main() {
|
|
var r Shape = Rectangle{Length: 3, Width: 4}
|
|
fmt.Printf("Type of r: %T, Area: %v, Perimeter: %v.", r, r.Area(), r.Perimeter())
|
|
}
|
|
```
|
|
|
|
## References
|
|
|
|
### Official resources
|
|
{: .-intro}
|
|
|
|
- [A tour of Go](https://tour.golang.org/welcome/1) _(tour.golang.org)_
|
|
- [Golang wiki](https://github.com/golang/go/wiki/) _(github.com)_
|
|
- [Effective Go](https://golang.org/doc/effective_go.html) _(golang.org)_
|
|
|
|
### Other links
|
|
{: .-intro}
|
|
|
|
- [Go by Example](https://gobyexample.com/) _(gobyexample.com)_
|
|
- [Awesome Go](https://awesome-go.com/) _(awesome-go.com)_
|
|
- [JustForFunc Youtube](https://www.youtube.com/channel/UC_BzFbxG2za3bp5NRRRXJSw) _(youtube.com)_
|
|
- [Style Guide](https://github.com/golang/go/wiki/CodeReviewComments) _(github.com)_
|