# Gopl 筆記 part2
[TOC]
## 5. Functions
### [Findlinks 解析](/rEz5vxg0Qq2L4PIZqsoHpw)
### [outline 解析](/FBN5V0XWQeWqCIZKXj7R8g)
### A tour of go
#### [Function values](https://tour.golang.org/moretypes/24)
* my practice:
* implement a function that compute the relationship of two values with appropriate handle function
#### Function closures
* Why do we use closure?
*
:::success
TODO
#### [Function closures](https://tour.golang.org/moretypes/25)
#### [Exercise: Fibonacci closure](https://tour.golang.org/moretypes/26)
:::
### [匿名函式與閉包](https://openhome.cc/Gossip/Go/Closure.html)
* :question:
* :question: How to implement a given function that filter the slice by given rules?
:::spoiler
```go=
// Define the type of handling function of filter
type Rule func(int) bool
// filter filter the given slice with handling predicate
func filter(origin []int, rule Rule) []int {
out := []int{}
for _, elem := range origin {
if rule(elem) {
out = append(out, elem)
}
}
return out
}
// Usage:
func main() {
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
fmt.Println("Input slice: ", data)
// Pass in data and the handling function to filter
// Filter the slice by elements less than 5
fmt.Println("Filter by number that is less than 5")
fmt.Println(filter(data, func(elem int) bool {
return elem < 5
}))
}
```
:::
* :question:
* 閉包的意義是?
* 閉包將變數本身關閉在自己的範疇中
* references variables declared outside of the function itself.
* 可以不通過 argument or return value 傳遞變數到對應的 handler
* 舉例說明
* [axis getter and setter](https://github.com/unknowntpo/sandbox/commit/87bc465fe58fc4e9c11f6d1d56b3dd1c4107a519)
* TODO: 找 closure 的應用
* [一級函式](https://openhome.cc/Gossip/Go/FirstClassFunction.html)
### 5.1 Function Definitions
* blank identifier
* omit unused variable
* :question: What if we want to ignore all of return values?
* [go playground](https://play.golang.org/p/yeoFkHAx4b4)
* passed by value
* passed by reference
### 5.2 Recursion
* 前情提要 (gopl 4.4 bst tree)
* findlinks1
* html document tree (BST)
* The main function parses the standard input as HTML, extracts the links using a recursive `visit` function, and prints each discovered link
* outline
* fetch
### 5.3 Multiple return values
* findlinks2
* no longer need to run fetch first
*
### 5.4 Errors
#### 5.4.1 Error-Handling Strategies
* Take `findLinks` as example
* example: `wait`
* 五種 error handling stratagies?
* 1. Propagate the error
* fail in subrutine become failure of calling routine
```go
resp, err := http.Get(url) // subroutine: http.Get()
if err != nil {
...
}
```
* :question:
* What does `fmt.Errorf()` do?
* format an error using `fmt.Sprintf()`
* return a new error value
* (so it can be concatinate!)
* Error 串接方法:
* 一率從 prefix 開始新增新的 error
* 2. Retry with given timeout
* e.g. [wait](https://github.com/adonovan/gopl.io/tree/master/ch5/wait)
#### 5.4.2 End of File (EOF)
see `charcount` program in `ch4.3 Maps`
### 5.5 Function values
* :question: What does Function values mean?
* [A Tour of Go](https://tour.golang.org/moretypes/24#:~:text=Functions%20are%20values%20too.,function%20arguments%20and%20return%20values.)
* :question: What can function value do?
* Function values may be used as function arguments and return values.
* :question: What does it meas `first-class values` ? (p.257)
```go=
func square(n int) int {return n * n}
f := square // f is function value
```
* example `outline2`
* show HTML DOM Tree with leveled structure
### 5.6 Anonymous Functions
* :question: What is anonymous function?
:::spoilerr
* Diff between `Anonymous function` and `Named functions`
* `Named functions`
* which can be declared at package level
* have `func` keyword + function name
* `Anonymous functions`
* no `func` keyword + function name
* :question: How to declare?
* use function literal
* its value is called `anonymous function`
:::
* function literal
* e.g. `squares`: return a the next square number each time it is called
* `e.g.toposort`
* `e.g. findLinks3`
* e.g. `links`
#### 5.6.1 Caveat: Capturing Iteration Variables
### 5.7 Variadic Functions
* e.g. `sum`
* e.g. `errorf`
### 5.8 Deferred Function Calls
* e.g. `title1`: output the title of given website
* e.g. `titles2`
* e.g. `ioutil`
* e.g. in 9.2, used `defer` unlock mutex
* e.g. improved `fetch` program (ch1.5)
### 5.9 Panic
* :question: What does it do?
* Capture runtime-error
* e.g. out-of bound array access
* nil pointer reference.
* e.g. `regexp` package: regexp.MustCompile()
* e.g. `defer1`
* e.g. `defer2`
### 5.10 Recover
* :question: What job does recover do?
* recover from panic
* e.g. `title3`
:::
### Defer, Panic, and Recover
* :question: How to use defer and recover to recover from panic?
:::spoiler
```go
package main
import "fmt"
func main() {
fmt.Println("Panic is comming (❁°͈▵°͈)")
defer func() {
if r := recover(); r != nil {
// Display the panic message
fmt.Println("What's happended?", r)
fmt.Println("Recover from panic finally ...")
} else {
// No panic, nothing to recover from
fmt.Println("Nothing happened, don't worry!")
}
}()
panic("Panic")
}
```
### [An Introduction to Programming in go](https://www.golang-book.com/books/intro):
#### [Functions](https://www.golang-book.com/books/intro/7)
* :question: What forms a closure?
* :question: What is panic?
* :question: How to use recover and defer to recover from panic?
* [Comit: Using defer and panic to recover from panic](https://github.com/unknowntpo/sandbox/commit/86ecf9bef8cd0a326f85b6f45c118c93d205f918)
* :question: **When does the defer function been executed?**
* Ans: [The Go blog - Defer, Panic, and Recover](https://blog.golang.org/defer-panic-and-recover)
:::spoiler
> # The Go Blog: Defer, Panic, and Recover
> A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.
:::success
* 也就是 `defer` 關鍵字所在的 function return 前,會把 使用到 defer 關鍵字的 function 以 LIFO 的方式一一呼叫,最後才會 return
:::
* :question: **How to use defer function to clean up resources?**
* Ans:[Commits: Using defer to handle cleanup function](https://github.com/unknowntpo/sandbox/commit/bd42312d2f59bc6add88c1b834122029ecfa999e)
:::success
施工中 :construction:
## 6. Methods
* Intro
* brief
* OOP
* encapsulation
* composition
* relationship between objrect, method
### 6.1 Method Declarations
* :question: What is a receiver? (p.297)
* example: geometry package (gopl/ch6/geometry)
* [experiment: pointer receiver addresss](https://play.golang.org/p/KFw2jzRbofe)
* :question: What's the diff between func, method call?
* :question: What is selector?
* can it be used in struct?
* :question: How to use package write by myself?
* see ch10. go tool and package
### 6.2 Methods with a pointer receivor
* :question: Why use pointers as receiver?
* Don't want to copy big data structure
:::
:::danger
Pointer receiver 只是把 object 的位置傳給 receiver 而已,
當
`r == nil` 時
`r.Insert(5)`
並不會更新 r 所指向的位置,所以 insert 後 r仍然指向 nil
:::
* :question: What's the diff between named type and pointer type?
* Can we use the same name in named type and pointer type in the same time?
* :information_source: 講到許多 pointer 在 method 的用法,包含 pointer to pointer
#### 6.2.1 Nil is a Valid Receiver Value
* 舉 `list == nil` 為例來說明,把 list 當 object 操作時,對他做 nil list 的比較的正確性
* e.g. `net/url` package
### 6.3 Composite types by struct embedding
## 7. Interface
### Go by example
* :dart: Implement geometry measuring function
* take an interface **geometry** as input
* print the area and perimeter of that geometry
* :question: How to use a function get multiple different method as input at the same time?
* using interface
* geometry (interface)
* rect (object)
* rect.area (method)
* rect.perim (method)
* circle (object)
* circle.area (method)
* circle.perim (method)
* Answer: [commits](https://github.com/unknowntpo/sandbox/commit/12580e589059fad1cd6dc7b78d86936a1fa536ed)
---
### A tour of Go
* [interface](https://tour.golang.org/methods/9)
* [errors](https://tour.golang.org/methods/20)
* :question: Why these code get
* ./prog.go:14:28: cannot use ErrNegativeSqrt(-2) (type ErrNegativeSqrt) as type error in return argument: ErrNegativeSqrt does not implement error (Error method has pointer receiver)
* [play](https://play.golang.org/p/JMOI80P26bf)
* ANs: 與 A tour of go - 19 比對就知道了!
* gopl p.335 有講到
* It is legal to call a *T method on an argument of type T so long as the argument is a variable; the compiler implicitly takes its address.
* [play](https://play.golang.org/p/HqLBqaj0GF8)
### GOPL
* :question:
* What does it mean "go's interfaces are satisfied implicitly"? (p.325)
* What is the type of interface type?
* abstract type
* like queue, stack
* unknown implementation
* Draw the relationship between
* `fmt.Fprintf()`
* `fmt.Printf()`
* `fmt.Sprintf()`
* What can be the concrete type of `io.Writer()`?
* `*os.File`
* `*bytes.Buffer`
* Re: gopl - ByteCounter
* [fmt.Stringer 解析](/cryNbGbHS4ONqZcbQMnugQ)
* [Exercise 7.4 - NewReader 解析](/B-SjSgvLQra20nvpgvBcnQ)
:::success
TODO:
:::
### 7.3 Interface Satisfaction
* :question: What is interface satisfaction?
* a type satisfiy an interface, when that type has all method defined in interface
:::success
TODO: 實作後嘗試了解這些
* p.335: `T`, `*T` receiver 問題
* s, &s 都可以 使用 .String() method
* 但是 只有 `&s` 可以 assign 給 type 為 fmt.Stringer 的 變數
* 因為只有 `&s` 擁有 String() method
* p.336:
* p.337: Type Assertion:
* interface get it's concrete type by type assertion
:::
## 8. Goroutines and Channels
### Go by example
* :question:
* Does go routine run in same address space?
* Yes,
* ref: a tour of go
* How to pass in args to anonymous function?
:::success
TODO: Wait for all goroutines to finish (for a more robust approach, use a [WaitGroup](https://gobyexample.com/waitgroups)).
:::
### gopl
#### example: Spinner
* :question: What does `\r` do?
* Ref: [Stack overflow](https://stackoverflow.com/questions/7372918/whats-the-use-of-r-escape-sequence#:~:text=8%20Answers&text=%5Cr%20is%20a%20carriage%20return,line%20of%20the%20terminal%20emulator.)
* :question: What is the difference betwen back quote (\`\`) and double quote ("") ?
* single quote (\'\'):
* define a rune or byte
* e.g.
* double quote (""):
* define a string
* it will honor any escape character
* back quote (\`\`):
* define a string
* without any escaping
* ref: [go by example - Double, Single and Back quotes in Go (Golang)
](https://golangbyexample.com/double-single-back-quotes-go/)
* :question: How to print a spinner with delay specified?
* :question: Why does spinner() stop ? Isn't it infinite loop?
### example: clock1 - sequential Clock Server
#### control flow of clock1
* main
* listener, err = net.Listen()
* conn, err = listener.Accept()
* handleConn(conn)
* io.WriteString(conn, time.Now().Format())
:::success
TODO: 了解 clock1 behavior
回答問題
:::
### example: netcat1 - go version of `nc` (netcat) -- arbitrary TCP and UDP connections and listens
* :question: What isthe different between TCP & HTTP?
* :question: clock1 為什麼不能用 browser access 呢?
* :question: What's the different between clock1 & clock2?
* :question: conn 代表什麼?往 conn 做 WriteString() 的意義是?
### example: reverb1
* :question: workflow?
```graphviz
digraph {
rankdir=LR
conn
input
echo
conn -> input [label="bufio.NewScanner()"]
input -> echo [label="input.Scan()"]
echo ->conn [label="echo(conn, shout, delay)"]
}
```
* :question: Trivial version 的 echo (p. 424) `io.Copy(dst, src)` 不能拿來修改輸入嗎?一定要用 reverb1 的方法?
* 差別在 buffer?
* :question: reverb1 與 clock1 的 handleConn() 差異是?
* :question: 有哪些對 io.Reader io.Writter 做讀寫的方法? 差異是?
* Write
* `os.Write()`
* `io.WriteString()`
* Read
* `bufio.Scanner.Scan()`
* `os.Read()`
* `ioutil.ReadAll(r io.Reader)`
* :question: What is a `bufio.Scanner` ?
### 8.4 Channels
* :question: Can channel be compared to
* 1. another channel
* 2. nil ?
:::spoler
1. Yes, it can be compare with the channel of same element type
2. Yes, because the zero value of a channel is nil
:::
* :question: What are the channel operations?
* send
* receive
* close
#### 8.4.1 Unbuffered channel (Synchronized channel)
* :question: In unbuffered channel, will it be blocked? explain the behavior of blocking
* Recap: a sender goroutine and receiver goroutine communicate through a channel
:::spoiler
* 1. if sender execute send operation first,
* sender will be blocked until receiver execute receive operation.
* 2. if receiver execute receive operation first,
* receiver will be blocked until sender execute send operation.
:::
:::success
* :bulb: Communicate over an unbuffered channel causes the sending and receiving goroutines to '*Synchronize*'
:::
* :question: What is a buffered channel in golang?
* a FIFO queue
* >Channels act as first-in-first-out queues.
* Ref: [go spec](https://golang.org/ref/spec#Channel_types)
* :question: `netcat2` v.s. `netcat3`?
* if `mustCopy(conn, os.Stdin)` are done, the main goroutine will stop,
* it doesn't wait for `go mustCopy(os.Stdout, conn)`
* :question: Why send `struct{}` not `bool`?
### [Go by Example: Channel Synchronization](https://gobyexample.com/channel-synchronization)
* :question: How to use a channel to wait until a job is done?
### [Go by Example: Channel Directions](https://gobyexample.com/channel-directions)
* Two type of channel direction
* Send-only (`chan<-`)
* we can only send data to a channel
* Receive-only (`<-chan`)
* we can only receive data from a channel
* What if we send data to receive-only channel
* Get compile-time error
* `./main.go:13:8: invalid operation: pings <- "a" (send to receive-only type <-chan string)`
### [Go by Example: Select](https://gobyexample.com/select)
* :question: How to wait for multiple goroutines to finish its job using channel and `select`?
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
## 11. Testing
### [profillingo: Basics of benchmarking, profiling and tracing with Go](https://github.com/samonzeweb/profilinggo)
### Testing - Go by Example
Ref: [Go by Example: Testing](https://gobyexample.com/testing)
* Given
* main.go
* We wanna test `IntMin()`
* Try to write tableDrive testing
* :question: What's is the constrain of test file name and function name?
:::spoiler
E.g. we wanna test main.go
Must contain *_test.go in test file name
:::
* :question: What is the field of structure `testing.T`?
* Sample code:
* `test_main.go`
:::spoiler
```go
package main
import (
"fmt"
"testing"
)
// Hard-coded testing function
func TestIntMinBasic(t *testing.T) { // what does testing.T means?
ans := IntMin(2, -2)
if ans != -2 {
t.Errorf("IntMin(2, -2) = %d; want -2", ans)
}
}
// Prefered testing function
func TestIntMinTableDriven(t *testing.T) {
var tests = []struct {
a, b int
want int
}{
{0, 1, 0},
{1, 0, 0},
{2, -2, -2},
{0, -1, -1},
{-1, 0, -1},
}
for _, tt := range tests {
testname := fmt.Sprintf("%d %d", tt.a, tt.b) // what does Sprintf() do
t.Run(testname, func(t *testing.T) {
ans := IntMin(tt.a, tt.b)
if ans != tt.want {
t.Errorf("IntMin(%d, %d) = %d; want %d", tt.a, tt.b, ans, tt.want)
}
})
}
}
```
:::
* Output:
:::spoiler
```shell
$ go test -v
=== RUN TestIntMinBasic
--- PASS: TestIntMinBasic (0.00s)
=== RUN TestIntMinTableDriven
=== RUN TestIntMinTableDriven/0_1
=== RUN TestIntMinTableDriven/1_0
=== RUN TestIntMinTableDriven/2_-2
=== RUN TestIntMinTableDriven/0_-1
=== RUN TestIntMinTableDriven/-1_0
--- PASS: TestIntMinTableDriven (0.00s)
--- PASS: TestIntMinTableDriven/0_1 (0.00s)
--- PASS: TestIntMinTableDriven/1_0 (0.00s)
--- PASS: TestIntMinTableDriven/2_-2 (0.00s)
--- PASS: TestIntMinTableDriven/0_-1 (0.00s)
--- PASS: TestIntMinTableDriven/-1_0 (0.00s)
PASS
ok _/Users/tacomaker/repo/sandbox/go/testing 0.005s
```
:::
* :question:` t.Run()` 作用是?
* :question:`t.Errorf()` 作用是?
* :question: `t.Run()` 為什麼要傳入整個 function 當作參數呢?
use showInfo() while first create playlist
get error
```shell
Creating playlist...
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x1094e80]
goroutine 1 [running]:
main.(*playlist).showInfo(0xc00007af68)
/Users/tacomaker/repo/sandbox/go/struct/linked_list_in_go/main.go:89 +0x30
main.main()
/Users/tacomaker/repo/sandbox/go/struct/linked_list_in_go/main.go:99 +0xfc
```
### 11.1 The go test tool
* :question: What are three type of function within `*_test.go` files treated specially?
:::spoiler
* tests
* function name: prefix `Test`
* go test report the result
* `PASS` or `FAIL`
* benchmarks
* function name: prefix `Benchmark`
* go test report the mean execution time of the operation
* examples
* machine-checked documentation
* function name: prefix `Example`
:::
### 11.2 Test functions
#### word1.go
* Goal: test our function `IsPalindrome()` in `word.go`
* Our target function:
:::spoiler
```go
// IsPalindrome reports whether s reads the same forward and backward.
// (Our first attempt.)
func IsPalindrome(s string) bool {
for i := range s {
if s[i] != s[len(s)-1-i] {
return false
}
}
return true
}
```
:::
* Test suit:
* Expected `PASS`
* `detartrated`
* `kayak`
* `été` ==**-->:interrobang: We got error here! it doesn't passed the test !**==
* Expected `FAIL`
* `palindrome`
* `A man, a plan, a canal: Panama`
* :question: Why `été` doesn't passed the test?
:::spoiler
Because `IsPalindrome()` used
==byte sequence==, not ==rune sequences!==
so that non-ASCII characters such as the `é` in `été` confuse it.
:::
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
* :question: How to run go test with specific test function?
:::spoiler
```shell
$ go test -run = "French|Canal" # regexp
```
:::
* :question: How to init an array of struct with `array literals`?
:::spoiler
* just like declarating an array,
* line 3 - 6 specify the data type of element in array `tests`
```go=1
// just like declarating an array
var a = [3]int{1, 2, 3}
var tests = []struct {
a, b int
want int
}{
{2, -2, -2},
{2, 3, 2},
{6, 10, 6},
{2, -7, -7},
{200, -100, -100},
}
```
:::
* :question: Why we can omit type of `test` in var declaration?
* [Composite literal](https://golang.org/ref/spec#Composite_literals)
* :information_source: Test function 中 prefix `Test` 之後的第一個字母也要大寫
* 就算你的待測試 function 叫做 `createPlaylist()` 也一樣
* 正確範例:
* Function to test: `createPlayList()`
* Test function: `TestCreatePlayList()`
* 錯誤範例:
* Test function:`TestcreatePlayList()`
* 不然會出現 warning
* `“testing: warning: no tests to run”`
* Ref: [testing](https://golang.org/pkg/testing/)
* :question: Why can we omit type in var declaration in test table?
* 可以參考 6.3 Composing Types by Struct Embedding
### 11.2.1 Randomized Testing
### 11.2.2 Testing a command
### 11.4 Benchmark Functions
### [如何在 Go 語言內寫效能測試](https://blog.wu-boy.com/2018/06/how-to-write-benchmark-in-go/)
* :question:
* What does `testing.B.N` mean?
* How to run benchmark without testing?
* `$ go test -bench=. -run=none -benchmem .`
* `-bench=.`
* ref: `go help testflag`
* Quote: To run all benchmarks, use '-bench .' or '-bench=.'.
* `-run=none`
* `-benchmem`
* `.`