/sys/stat.h included 37 times (1984 test, probably much worse now)
google build of a binary that totaled 4.2 MB of source turned into 8GB seen by compiler
- concurrency, multi-core support built-in
- memory allocation
## Brief tour
(from perspective of C)
- package/include system
- interfaces
- duck typing
- slices vs arrays
- maps
- typesafe
- goroutines
- channels
- garbage collection
## Preliminaries:
- everything in GOPATH
-**go** build/install/get/run/...
- emacs go-mode comes w/ distribution
### Gotchas:
- all passed by value: pointers, but also stucts, arrays (use slices)
- no pointer arith
- ++ exists, but not expression
- no implicit conversions, but int(4.3)
- no type aliases
-`type dint int` now distinct types
- can add methods to user-defined types
- no ternary
**And**:
- no constructors/destructors
- no default args
- no exceptions (but panic/recover)
- no arrays of mixed type
## Packages:
- everything is part of a package
- variables, methods exported by starting with capitalized name
package "dss"
func invisible(int one) {
...
}
func Visible(int one) {
...
}
called:
import "blah/pete/dss"
dss.Visible(...)
## Modules
- packages are in modules
- modules encode dependencies, and can be used to fetch them, e.g.:
```
go mod init
g mod tidy
```
## Memory allocation
- allocation:
- new() zeros,
- make() initializes, for channels, maps, slices...
## Arrays
- fixed size
- passed by value to funcs
- arrays are defined using a fixed size, e.g. `sa :
[3]Int`, or
```
var sa [3]int = [3]int{1, 2, 3}
sb := [3]int{1, 2, 3}
sb2 := [3]int{0:1, 2:3}
sc := [...]int{1, 2, 3}
fmt.Println(sa)
fmt.Println(sb)
fmt.Println(sb2)
fmt.Println(sc)
```
## Slices!
sl := arr[0:2]
fmt.Println(sl)
sl2 := []int{4, 5, 6}
fmt.Println(sl2)
sl3 := append(sl2, 7, 8)
fmt.Println(sl3)
sl2 = append(sl2, 9, 10)
fmt.Println(sl2)
fmt.Println(sl3)
[play](https://play.golang.org/p/eMseomDmtBl)
## Maps
type Vertex struct {
Lat, Lon, float64
}
m := map[string] Vertex {
"one" : {40.8, -74.5},
"two" : {41.8, -75.5},
}
keys can be anything that can be sorted (strings, int..)
= m["four"]
m["four"] = ...
Returns default value if no exist.
m["four"], ok = ...
"ok" *true* if in map
## Functions:
func blah(i int...) int {
func blah(i int...) (int, int) {
### Methods:
func (d *Myobj) blah(i int...) (int, int) {
### Interfaces:
- not objects
- just method signatures
- implicit
type Shape interface {
func Area() int
}
ANY type that implements the 'Area' method is implicitly a Shape
How?
Let's say I have another object:
type Circle struct {
radius int
....
}
Now I define:
func (n *Circle) Area() int { // receiver/name/args/return
....
}
A Circle is now a Shape!
- implicit (Duck typing)
- variables
c := new(Circle)
var s Shape
s = c
Can also define:
func (n *Rect) Area() int ...
var r Rect
s = &r
And a Rect is now a shape.
*Why maybe no good?*
### Cool things: stack is in the heap, so:
Allocation!
func() *int {
id := 2
return &id
}
### Anonymous functions == Closures!
func intSeq() func() int {
i := 0
return func() int {
i += 1
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt())
}
[play](https://play.golang.org/p/KIefyeKFEP)
### More fun: fib!
func fib() func() int {
i1, i2 := 0, 1
return func() (r int) {
r = i1
i1, i2 = i2, i1+i2
return
}
}
func main() {
f := fib()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
[play](https://play.golang.org/p/jLDSk4Wend)
## Goroutines
Lightweight threads:
f(x,y)
go f(x,y)
Sync w/ *channels*, not explicit locks...
package main
import (
"fmt"
"time"
)
func slowFunc(done chan int) {
time.Sleep(2*time.Second)
fmt.Println("goroutine finish...")
done <- 1
}
func main() {
ch := make(chan int)
go slowFunc(ch)
fmt.Println("waiting...")
<-ch
fmt.Println("done!")
}
[play](https://go.dev/play/p/96dOj_Vp4m4)
blocking sends, receives until other side ready
ch := make(chan int, 5) // buffered
sync library
# Panic / Defer / Recover
```
package main
import (
"fmt"
"github.com/pkg/errors"
)
func A() {
defer fmt.Println("A")
defer func() {
if r := recover(); r != nil {
fmt.Printf("Panic: %+v\n", r)
}
}()
B()
}
func B() {
defer fmt.Println("B")
C()
}
func C() {
defer fmt.Println("C")
Break()
}
func Break() {
defer fmt.Println("D")
// panic(errors.New("the show must go on"))
fmt.Println("after panic")
}
func main() {
A()
fmt.Printf("After 'A'\n")
}
```
[play](https://go.dev/play/p/xNP3zxVI3SB)
"Note that unlike some languages which use exceptions for handling of many errors, in Go it is idiomatic to use error-indicating return values wherever possible."