Go
===
## Environment setup & debug
### Install go compiler
https://go.dev/dl/
### Install vscode extension for go
https://marketplace.visualstudio.com/items?itemName=golang.go
### Install delve debugger
Install in VSCode
> \> Go: Install/Update Tools
- debugging with gdb
https://go.dev/doc/gdb
## Module & package
Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package.
Choose a module path (we'll use example/user/hello) and create a go.mod file
```
$ go mod init example/user/hello
go: creating new go.mod: module example/user/hello
$ cat go.mod
module example/user/hello
go 1.16
```
Create package morestrings at $HOME/hello/morestrings/reverse.go
```go=
// Package morestrings implements additional functions to manipulate UTF-8
// encoded strings, beyond what is provided in the standard "strings" package.
package morestrings
// 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)
}
```
Call `ReverseRunes()` in $HOME/hello/hello.go `main()`
```go=
package main
import (
"fmt"
"example/user/hello/morestrings"
"github.com/google/go-cmp/cmp"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
fmt.Println(cmp.Diff("Hello World", "Hello Go"))
}
```
The `go mod tidy` command adds missing module requirements for imported packages and removes requirements on modules that aren't used anymore.
```
$ go mod tidy
go: finding module for package github.com/google/go-cmp/cmp
go: found github.com/google/go-cmp/cmp in github.com/google/go-cmp v0.5.4
$ cat go.mod
module example/user/hello
go 1.16
require github.com/google/go-cmp v0.5.4
```
Add a test to the morestrings package by creating the file $HOME/hello/morestrings/reverse_test.go containing the following Go code.
```go=
package morestrings
import "testing"
func TestReverseRunes(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := ReverseRunes(c.in)
if got != c.want {
t.Errorf("ReverseRunes(%q) == %q, want %q", c.in, got, c.want)
}
}
}
```
Then run the test with go test:
```
$ cd $HOME/hello/morestrings
$ go test
PASS
ok example/user/hello/morestrings 0.165s
```
- [Using Go Modules](https://go.dev/blog/using-go-modules)
- [How to Write Go Code](https://go.dev/doc/code)
## Basic syntax
### Basic data types
Go supports following built-in basic types:
```
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128
```
The size of uintptr, int and uint values n memory are implementation-specific. Generally, The size of int and uint values are 4 on 32-bit architectures, and 8 on 64-bit architectures. The size of uintptr value must be large enough to store the uninterpreted bits of any memory address.
```go=
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
var num int
var num1 int = 1
num2 := 2
/*
In a short variable declaration,
all items at the left of the := sign must pure identifiers.
*/
// const num3 := 3 // Error
const num3 = 3
fmt.Println(num, num1, num2, num3)
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
// 0 1 2 3
// Type: bool Value: false
// Type: uint64 Value: 18446744073709551615
// Type: complex128 Value: (2+3i)
```
> Ref: https://go.dev/tour/basics/11
Each type has a zero value. The zero value of a type can be viewed as the default value of the type.
- The zero value of a boolean type is false.
- The zero value of a numeric type is zero, though zeros of different numeric types may have different sizes in memory.
- The zero value of a string type is an empty string.
```go=
package main
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
// 0 0 false ""
```
> Ref: https://go.dev/tour/basics/12
### Pointer
**Pointer, slice and map are reference type**
```go=
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i // point to i
fmt.Println(*p) // read i through the pointer
*p = 21 // set i through the pointer
fmt.Println(i) // see the new value of i
p = &j // point to j
*p = *p / 37 // divide j through the pointer
fmt.Println(j) // see the new value of j
// p++ // Error. Unlike C, Go has no pointer arithmetic.
}
```
> Ref: https://go.dev/tour/moretypes/1
### Structs
```go=
package main
import "fmt"
type Vertex struct {
X, Y int
}
var (
v1 = Vertex{1, 2} // has type Vertex
v2 = Vertex{X: 1} // Y:0 is implicit
v3 = Vertex{} // X:0 and Y:0
p = &Vertex{1, 2} // has type *Vertex
)
func main() {
fmt.Println(v1, p, v2, v3)
}
// {1 2} &{1 2} {1 0} {0 0}
```
> Ref: https://go.dev/tour/moretypes/5
### Slice & Array
This is an array literal: `[3]bool{true, true, false}`
```go=
package main
import "fmt"
func main() {
var a [2]string
a[0] = "Hello"
a[1] = "World"
fmt.Println(a[0], a[1])
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13}
fmt.Println(primes)
}
// Hello World
// [Hello World]
// [2 3 5 7 11 13]
```
> Ref: https://go.dev/tour/moretypes/6
A slice literal is like an array literal without the length.
And this creates the same array as above, then builds a slice that references it: `[]bool{true, true, false}`
```go=
package main
import "fmt"
func main() {
q := []int{2, 3, 5, 7, 11, 13}
fmt.Println(q)
r := []bool{true, false, true, true, false, true}
fmt.Println(r)
s := []struct {
i int
b bool
}{
{2, true},
{3, false},
{5, true},
{7, true},
{11, false},
{13, true},
}
fmt.Println(s)
}
// [2 3 5 7 11 13]
// [true false true true false true]
// [{2 true} {3 false} {5 true} {7 true} {11 false} {13 true}]
```
> Ref: https://go.dev/tour/moretypes/9
The length of a slice is the number of elements it contains.
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.
```go=
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13}
printSlice(s)
// Slice the slice to give it zero length.
s = s[:0]
printSlice(s)
// Extend its length.
s = s[:4]
printSlice(s)
// Drop its first two values.
s = s[2:]
printSlice(s)
a := make([]int, 5) // len(a)=5
printSlice(a)
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
printSlice(b)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
// len=6 cap=6 [2 3 5 7 11 13]
// len=0 cap=6 []
// len=4 cap=6 [2 3 5 7]
// len=2 cap=4 [5 7]
// len=5 cap=5 [0 0 0 0 0]
// len=0 cap=5 []
```
> Ref: https://go.dev/tour/moretypes/11
Multi-Dimensional slices
```go=
package main
import "golang.org/x/tour/pic"
/*
dx
dy ----
| |
| |
----
*/
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for y := range(pic) {
pic[y] = make([]uint8, dx)
}
for y := 0; y < dy; y++ {
for x := 0; x < dx; x++ {
pic[y][x] = uint8((x + y) / 2)
}
}
return pic
}
func main() {
pic.Show(Pic)
}
```
> Ref: https://go.dev/tour/moretypes/18
Subslice and array
```go=
package main
import "fmt"
func main() {
a := [...]int{0, 1, 2, 3, 4, 5, 6}
s0 := a[:] // <=> s0 := a[0:7:7]
s1 := s0[:] // <=> s1 := s0
s2 := s1[1:3] // <=> s2 := a[1:3]
s3 := s1[3:] // <=> s3 := s1[3:7]
s4 := s0[3:5] // <=> s4 := s0[3:5:7]
s5 := s4[:2:2] // <=> s5 := s0[3:5:5]
s6 := append(s4, 77)
s7 := append(s5, 88)
s8 := append(s7, 66)
s3[1] = 99
fmt.Println(len(s2), cap(s2), s2) // 2 6 [1 2]
fmt.Println(len(s3), cap(s3), s3) // 4 4 [3 99 77 6]
fmt.Println(len(s4), cap(s4), s4) // 2 4 [3 99]
fmt.Println(len(s5), cap(s5), s5) // 2 2 [3 99]
fmt.Println(len(s6), cap(s6), s6) // 3 4 [3 99 77]
fmt.Println(len(s7), cap(s7), s7) // 3 4 [3 4 88]
fmt.Println(len(s8), cap(s8), s8) // 4 4 [3 4 88 66]
}
```

> https://go101.org/article/container.html
### Map
```go=
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m1 = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
// v := m["Answer"] // panic
}
// The value: 42
// The value: 48
// The value: 0
// The value: 0 Present? false
```
> Ref: https://go.dev/tour/moretypes/22
### Function
Functions are value too.
```go=
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
```
> Ref: https://go.dev/tour/moretypes/24
Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is "bound" to the variables.
For example, the `adder` function returns a closure. Each closure is bound to its own sum variable.
```go=
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
// 0 0
// 1 -2
// 3 -6
// 6 -12
// 10 -20
// 15 -30
// 21 -42
// 28 -56
// 36 -72
// 45 -90
```
### Methods
Go does not have classes. However, you can define methods on types.
```go=
package main
import (
"fmt"
"math"
)
type MyFloat float64
// cannot define new methods on non-local type float32
/*
func (f float32) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
*/
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
}
```
> Ref: https://go.dev/tour/methods/3
### Interfaces
```go=
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
describe(i)
i.M()
i = &T{"hello"}
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
// (<nil>, *main.T)
// <nil>
// (&{hello}, *main.T)
// hello
```
> Ref: https://go.dev/tour/methods/12
An empty interface may hold values of any type. (Every type implements at least zero methods.)
Empty interfaces are used by code that handles values of unknown type. For example, `fmt.Print` takes any number of arguments of type `interface{}`.
```go=
package main
import "fmt"
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
// (<nil>, <nil>)
// (42, int)
// (hello, string)
```
> Ref: https://go.dev/tour/methods/14
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.
```go=
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // panic
fmt.Println(f)
}
// hello
// hello true
// 0 false
// panic: interface conversion: interface {} is string, not float64
```
The declaration in a type switch has the same syntax as a type assertion i.(T), but the specific type T is replaced with the keyword type.
```go=
package main
import "fmt"
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
// Twice 21 is 42
// "hello" is 5 bytes long
// I don't know about type bool!
```
> Ref: https://go.dev/tour/methods/16
A Stringer is a type that can describe itself as a string. The fmt package (and many others) look for this interface to print values.
`
type Stringer interface {
String() string
}`
```go=
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
// Arthur Dent (42 years) Zaphod Beeblebrox (9001 years)
```
> Ref: https://go.dev/tour/methods/17
A nil interface value holds neither value nor concrete type.
**Interface is not nil if it assigned by underlying type.**
```go=
package main
import "fmt"
type I interface {
M()
}
type myInt int32
func (myint *myInt) M() {
fmt.Println("myInt.M()")
}
func getInterfaceWithMyInt() I {
var myint *myInt
return myint // return a interface assigned by underlying type
}
func main() {
var i I
describe(i)
// i.M() // panic: runtime error
fmt.Println("i is nil:", i == nil)
i = getInterfaceWithMyInt()
describe(i)
i.M()
fmt.Println("i is nil:", i == nil)
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
// (<nil>, <nil>)
// i is nil: true
// (<nil>, *main.myInt)
// myInt.M()
// i is nil: false
```
> Ref: https://go.dev/tour/methods/13
### Errors
Go have no exception handling mechanism.
The error type is a built-in interface similar to `fmt.Stringer`:
`
type error interface {
Error() string
}
`
A nil error denotes success; a non-nil error denotes failure.
```go=
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
// at 2009-11-10 23:00:00 +0000 UTC m=+0.000000001, it didn't work
```
> Ref: https://go.dev/tour/methods/19
**Avoid return an interface was assigned by underlying type.**
In `runSurprise()`, may not return nil by default.
```go=
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run(num int) (int, error) {
if num < 0 {
return num, &MyError{
time.Now(),
"in run(), it didn't work",
}
}
return num, nil
}
func runSurprise(num int) (int, error) {
var myerror *MyError
if num < 0 {
myerror = &MyError{
time.Now(),
"in runSurprise(), it didn't work",
}
}
return num, myerror
}
func main() {
if ret, err := run(0); err != nil {
fmt.Println("return by run()")
fmt.Println(ret, err)
}
if ret, err := runSurprise(0); err != nil {
fmt.Println("return by runSurprise()")
fmt.Println(ret, err)
}
}
// return by runSurprise()
// 0 <nil>
```
> Ref: https://go.dev/tour/methods/19
### Defer
Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.
```go=
package main
import (
"fmt"
)
func main() {
fmt.Println("main() is start")
for i := 0; i < 3; i++ {
defer fmt.Println(i)
}
fmt.Println("main() is end")
}
// main() is start
// main() is end
// 2
// 1
// 0
```
Defer is commonly used to simplify functions that perform various clean-up actions.
```go=
var m sync.Mutex
func f1() {
m.Lock()
defer m.Unlock()
doSomething()
}
```
### Panic and Recover
`func panic(v interface{})`
We can call the built-in `panic` function to create a panic to make the current goroutine enter panicking status.
Panicking is another way to make a function return. Once a panic occurs in a function call, the function call returns immediately and enters its exiting phase.
`func recover() interface{}`
By calling the built-in `recover` function in a deferred call, an alive panic in the current goroutine can be removed so that the current goroutine will enter normal calm status again.
```go=
package main
import "fmt"
func main() {
defer func() {
fmt.Println("exit normally.")
}()
fmt.Println("hi!")
defer func() {
v := recover()
fmt.Println("recovered:", v)
}()
panic("bye!")
fmt.Println("unreachable")
}
```
**If a panicking goroutine exits without being recovered, it will make the whole program crash.**
```go=
package main
import "fmt"
func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
// if r := recover(); r != nil {
// fmt.Println("Recovered in f", r)
// }
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
if i > 3 {
fmt.Println("Panicking!")
panic(fmt.Sprintf("%v", i))
}
defer fmt.Println("Defer in g", i)
fmt.Println("Printing in g", i)
g(i + 1)
}
// Calling g.
// Printing in g 0
// Printing in g 1
// Printing in g 2
// Printing in g 3
// Panicking!
// Defer in g 3
// Defer in g 2
// Defer in g 1
// Defer in g 0
// panic: 4
// goroutine 1 [running]:
// main.g(0x4)
// /tmp/sandbox874700665/prog.go:24 +0x1d9
// main.g(0x3)
// /tmp/sandbox874700665/prog.go:28 +0x125
// main.g(0x2)
// /tmp/sandbox874700665/prog.go:28 +0x125
// main.g(0x1)
// /tmp/sandbox874700665/prog.go:28 +0x125
// main.g(0x0)
// /tmp/sandbox874700665/prog.go:28 +0x125
// main.f()
// /tmp/sandbox874700665/prog.go:17 +0x74
// main.main()
// /tmp/sandbox874700665/prog.go:6 +0x13
```
Generally, panics are used for logic errors, such as careless human errors. Logic errors should never happen at run time. If they happen, there must be bugs in the code. On the other hand, non-logic errors are hard to absolutely avoid at run time. In other words, non-logic errors are errors happening in reality. Such errors should not cause panics and should be explicitly returned and handled properly.
**Some Fatal Errors Are Not Panics and They Are Unrecoverable**
For the standard Go compiler, some fatal errors, such as stack overflow and out of memory are not recoverable. Once they occur, program will crash.
[Some Panic/Recover Use Cases](https://go101.org/article/panic-and-recover-use-cases.html)
## Generics
### Generic function
Go functions can be written to work on multiple types using type parameters.
```go=
package main
import "fmt"
// Index returns the index of x in s, or -1 if not found.
func Index[T comparable](s []T, x T) int {
for i, v := range s {
// v and x are type T, which has the comparable
// constraint, so we can use == here.
if v == x {
return i
}
}
return -1
}
func main() {
// Index works on a slice of ints
si := []int{10, 20, 15, -10}
fmt.Println(Index(si, 15))
// Index also works on a slice of strings
ss := []string{"foo", "bar", "baz"}
fmt.Println(Index(ss, "hello"))
}
// 2
// -1
```
Linked list example
```go=
package main
import (
"errors"
"fmt"
)
// List represents a singly-linked list that holds
// values of any type.
type Node[T any] struct {
next *Node[T]
val T
}
type List[T any] struct {
begin *Node[T]
}
func (list *List[T]) Pushback(val T) {
node := Node[T]{nil, val}
if list.begin == nil {
list.begin = &node
return
}
for p := list.begin; ; {
if p.next == nil {
p.next = &node
return
}
p = p.next
}
}
func (list *List[T]) Popfront() (T, error) {
if list.begin == nil {
return *new(T), errors.New("List is empty")
}
val := list.begin.val
list.begin = list.begin.next
return val, nil
}
func main() {
list := &List[int]{nil}
list.Pushback(1)
list.Pushback(2)
list.Pushback(3)
list.Pushback(4)
for {
val, ok := list.Popfront()
if ok != nil {
break
}
fmt.Println(val)
}
}
```
## Concurrency
### Goroutine
Goroutines are maintained and scheduled by the language runtime instead of the operating systems. The cost of memory consumption and context switching, of a goroutine is much lesser than an OS thread.
**Goroutines run in the same address space, so access to shared memory must be synchronized.**
```go=
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
// world
// hello
// world
// hello
// hello
// world
// world
// hello
// hello
```
### WaitGroup
- Add method: used to register the number of new tasks.
- Done method: used to notify that a task is finished.
- Wait method: makes the caller goroutine become blocking until all registered tasks are finished.
```go=
package main
import (
"log"
"math/rand"
"time"
"sync"
)
var wg sync.WaitGroup
func SayGreetings(greeting string, times int) {
for i := 0; i < times; i++ {
log.Println(greeting)
d := time.Second * time.Duration(rand.Intn(5)) / 2
time.Sleep(d)
}
// Notify a task is finished.
wg.Done() // <=> wg.Add(-1)
}
func main() {
rand.Seed(time.Now().UnixNano()) // needed before Go 1.20
log.SetFlags(0)
wg.Add(2) // register two tasks.
go SayGreetings("hi!", 10)
go SayGreetings("hello!", 10)
wg.Wait() // block until all tasks are finished.
}
```

A blocking goroutine can only be unblocked by an operation made in another goroutine. If all goroutines in a Go program are in blocking state, then all of them will stay in blocking state forever. This can be viewed as an **overall deadlock**. When this happens in a program, the standard Go runtime will try to crash the program.
The following program will crash, after two seconds:
```go=
package main
import (
"sync"
"time"
)
var wg sync.WaitGroup
func main() {
wg.Add(1)
go func() {
time.Sleep(time.Second * 2)
wg.Wait()
}()
wg.Wait()
}
// fatal error: all goroutines are asleep - deadlock!
```
### Channel
Communicating by sharing memory and sharing memory by communicating are two programming manners in concurrent programming. When goroutines **communicate by sharing memory, we use traditional concurrency synchronization techniques**, such as mutex locks, to protect the shared memory to prevent data races. We can **use channels to implement sharing memory by communicating**.
We can view a channel as an **internal FIFO (first in, first out) queue** within a program. Some goroutines send values to the queue (the channel) and some other goroutines receive values from the queue.
Channel types can be bi-directional or single-directional. Assume T is an arbitrary type,
- `chan T` denotes a bidirectional channel type. Compilers allow both receiving values from and sending values to bidirectional channels.
- `chan<- T` denotes a send-only channel type. Compilers don't allow receiving values from send-only channels.
- `<-chan T` denotes a receive-only channel type. Compilers don't allow sending values to receive-only channels.
Unbuffered channel
```go=
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int) // an unbuffered channel
go func(ch chan<- int, x int) {
time.Sleep(time.Second)
// <-ch // fails to compile
// Send the value and block until the result is received.
ch <- x*x // 9 is sent
}(c, 3)
done := make(chan struct{})
go func(ch <-chan int) {
// Block until 9 is received.
n := <-ch
fmt.Println(n) // 9
// ch <- 123 // fails to compile
time.Sleep(time.Second)
done <- struct{}{}
}(c)
// Block here until a value is received by
// the channel "done".
<-done
fmt.Println("bye")
}
```
Buffered channel
```go=
package main
import "fmt"
func main() {
c := make(chan int, 2) // a buffered channel
c <- 3
c <- 5
close(c)
fmt.Println(len(c), cap(c)) // 2 2
x, ok := <-c
fmt.Println(x, ok) // 3 true
fmt.Println(len(c), cap(c)) // 1 2
x, ok = <-c
fmt.Println(x, ok) // 5 true
fmt.Println(len(c), cap(c)) // 0 2
x, ok = <-c
fmt.Println(x, ok) // 0 false
x, ok = <-c
fmt.Println(x, ok) // 0 false
fmt.Println(len(c), cap(c)) // 0 2
close(c) // panic!
// The send will also panic if the above
// close call is removed.
c <- 7
}
```
Only the sender should close a channel, never the receiver. Sending on a closed channel will cause a panic.
Channels aren't like files; you don't usually need to close them. Closing is only necessary when the receiver must be told there are no more values coming.

[More channel use cases](https://go101.org/article/channel-use-cases.html)
### Select
A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.
```go=
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 5; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
// 0
// 1
// 1
// 2
// 3
// quit
```
### Common Concurrent Programming Mistakes
- [Common Concurrent Programming Mistakes](https://go101.org/article/concurrent-common-mistakes.html)
### GMP scheduler model
- [Golang GMP模型](https://hackmd.io/@zhegen/SJxZMkIdc#Goroutine)
## Memory management
### Allocate memory
`new(T)`
`make(T, args)`
### Collect memory
- [Memory Blocks](https://go101.org/article/memory-block.html)
## Unit test
https://go.dev/doc/tutorial/add-a-test
## FFI
### Type conversion
## Reference
- [Learn Go in 3 Hours - Oreilly online course](https://learning.oreilly.com/videos/learn-go-in/9781788992053/)
- [Go 101](https://go101.org/article/101.html)
- [Go tour](https://go.dev/tour/list)
> Simple exercises on playground