├── README.md └── src ├── ch1 ├── hello │ └── hello_world.go └── main │ └── main.go ├── ch10 └── func │ └── func_test.go ├── ch11 ├── customer_type │ └── customer_type_test.go ├── encapsulation │ └── encap_test.go └── interface │ └── interface_test.go ├── ch12 └── extension │ └── extension_test.go ├── ch13 ├── empty_interface │ └── empty_interface_test.go └── polymorphsim │ └── polymorphsim_test.go ├── ch14 ├── error │ └── error_test.go └── panic_recover │ └── panic_recover_test.go ├── ch15 ├── client │ └── package_test.go ├── remote_package │ └── remote_package_test.go └── series │ └── my_series.go ├── ch16 └── gorutine │ └── groutine_test.go ├── ch17 └── share_mem │ └── share_mem_test.go ├── ch18 └── csp │ └── async_service_test.go ├── ch19 └── select │ └── select_test.go ├── ch2 ├── constant_test │ └── constant_try_test.go └── fib │ └── fib_test.go ├── ch20 └── channel_close │ └── channel_close_test.go ├── ch20_1 └── cancel_by_close │ └── cancel_test.go ├── ch20_2 └── cancel_by_close │ └── cancel_test.go ├── ch21 └── singleton │ └── once_test.go ├── ch22 └── util_anyone_reply │ └── frist_response_test.go ├── ch23 └── until_all_reply │ └── untill_all_test.go ├── ch24 └── obj_pool │ ├── obj_pool.go │ └── obj_pool_test.go ├── ch25 └── obj_cache │ └── sync_pool_test.go ├── ch3 └── type_test │ └── type_test.go ├── ch32 └── unit_test │ ├── functions.go │ └── functions_test.go ├── ch33 └── benchmark │ └── concat_string_test.go ├── ch34 └── bdd │ └── bdd_spec_test.go ├── ch35 └── reflect │ └── reflect_test.go ├── ch36 └── flexible_reflect_test.go ├── ch38 └── unsafe_programming │ └── unsafe_test.go ├── ch39 └── pipe_filter │ ├── filter.go │ ├── split_filter.go │ ├── split_filter_test.go │ ├── straigt_pipeline.go │ ├── straigt_pipeline_test.go │ ├── sum_filter.go │ ├── sum_filter_test.go │ ├── to_int_filter.go │ └── to_int_filter_test.go ├── ch4 └── operator_test │ └── operator_test.go ├── ch40 └── microkernel │ ├── agent.go │ └── agent_test.go ├── ch41 └── json │ ├── embedded_json_test.go │ └── struct_def.go ├── ch42 └── easyjson │ ├── embedded_json_test.go │ ├── struct_def.go │ └── struct_def_easyjson.go ├── ch43 ├── hello_http │ └── hello_http.go └── roa │ └── resource_oriented_arc.go ├── ch44 └── tools │ ├── file │ ├── cpuporf.png │ └── prof.go │ └── http │ └── fb_server.go ├── ch45 ├── easyjsonls.png ├── list.png ├── ls.png ├── optimization_test.go ├── optmization.go ├── structs.go ├── top-cum.png ├── top.png ├── yhbench.png └── yhcreatecpuprof.png ├── ch46 ├── lock │ └── lock_test.go └── maps │ ├── concurrent_map_benchmark_adapter.go │ ├── map_benchmark_test.go │ ├── rw_map.go │ └── sync_map_benchmark_adapter.go ├── ch47 └── gc_friendly │ ├── auto_growing │ └── auto_growing_test.go │ └── pass_ref │ ├── pass_array_test.go │ ├── ref.png │ └── val.png ├── ch48 └── concat_string_test.go ├── ch5 └── loop │ └── loop_test.go ├── ch6 ├── array_test │ └── array_test.go └── slice_test │ └── slice_test.go ├── ch7 └── map │ └── map_test.go ├── ch8 └── map │ └── map_test.go ├── ch9 └── string │ ├── string_fun_test.go │ └── string_test.go ├── eventcenter └── eventcenter_test.go └── mianshi └── mianshi_test.go /README.md: -------------------------------------------------------------------------------- 1 | # golearning 2 | go语言学习笔记 3 | -------------------------------------------------------------------------------- /src/ch1/hello/hello_world.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | if len(os.Args) > 1 { 10 | fmt.Println("Hello World", os.Args[1]) 11 | } else { 12 | fmt.Println("Hello World") 13 | } 14 | os.Exit(0) 15 | } 16 | -------------------------------------------------------------------------------- /src/ch1/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println("Hello World go!") 9 | } 10 | -------------------------------------------------------------------------------- /src/ch10/func/func_test.go: -------------------------------------------------------------------------------- 1 | package func_test 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func returnMultiValues() (int, int) { 11 | return rand.Intn(10), rand.Intn(20) 12 | } 13 | 14 | func timeSpent(inner func(op int) int) func(op int) int { 15 | return func(n int) int { 16 | start := time.Now() 17 | ret := inner(n) 18 | 19 | fmt.Println("time spent:", time.Since(start).Seconds()) 20 | return ret 21 | } 22 | } 23 | 24 | func slowFun(op int) int { 25 | time.Sleep(time.Second * 1) 26 | return op 27 | } 28 | 29 | func TestFn(t *testing.T) { 30 | a, _ := returnMultiValues() 31 | t.Log(a) 32 | tsSF := timeSpent(slowFun) 33 | t.Log(tsSF(10)) 34 | } 35 | 36 | func Sum(ops ...int) int { 37 | s := 0 38 | for _, op := range ops { 39 | s += op 40 | } 41 | return s 42 | } 43 | 44 | func TestVarParam(t *testing.T) { 45 | t.Log(Sum(1, 2, 3, 4)) 46 | t.Log(Sum(1, 2, 3, 4, 5)) 47 | } 48 | 49 | func Clear() { 50 | fmt.Println("Clear resources") 51 | } 52 | 53 | func TestDefer(t *testing.T) { 54 | defer Clear() 55 | t.Log("started") 56 | panic("Fatal error") 57 | fmt.Println("End") 58 | } 59 | -------------------------------------------------------------------------------- /src/ch11/customer_type/customer_type_test.go: -------------------------------------------------------------------------------- 1 | package customer_type_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | type IntConv func(op int) int 10 | 11 | func timeSpent(inner func(op int) int) IntConv { 12 | return func(n int) int { 13 | start := time.Now() 14 | ret := inner(n) 15 | fmt.Println("time spent:", time.Since(start).Seconds()) 16 | return ret 17 | } 18 | } 19 | 20 | func slowFun(op int) int { 21 | time.Sleep(time.Second * 1) 22 | return op 23 | } 24 | 25 | func TestFn(t *testing.T) { 26 | tsSF := timeSpent(slowFun) 27 | t.Log(tsSF(10)) 28 | } 29 | -------------------------------------------------------------------------------- /src/ch11/encapsulation/encap_test.go: -------------------------------------------------------------------------------- 1 | package encapsulation 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unsafe" 7 | ) 8 | 9 | type Employee struct { 10 | Id string 11 | Name string 12 | Age int 13 | } 14 | 15 | func TestCreateEmployee(t *testing.T) { 16 | e := Employee{"0", "Bob", 20} 17 | e1 := Employee{Name: "Bob", Age: 20} 18 | e2 := new(Employee) 19 | e2.Id = "2" 20 | e2.Name = "Rose" 21 | t.Log(e) 22 | t.Log(e1) 23 | t.Log(e1.Id) 24 | t.Log(e2) 25 | t.Logf("e is %T", e) 26 | t.Logf("e2 is %T", e2) 27 | } 28 | 29 | func (e Employee) String() string { 30 | fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) 31 | return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age) 32 | } 33 | 34 | //func (e *Employee) String() string { 35 | // fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) 36 | // return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age) 37 | //} 38 | 39 | func TestStructOperations(t *testing.T) { 40 | e := Employee{"0", "Bob", 20} 41 | fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) 42 | t.Log(e.String()) 43 | } 44 | -------------------------------------------------------------------------------- /src/ch11/interface/interface_test.go: -------------------------------------------------------------------------------- 1 | package interface__test 2 | 3 | import "testing" 4 | 5 | type Progarmmer interface { 6 | WriteHelloWorld() string 7 | } 8 | 9 | type GoProgarmmer struct { 10 | } 11 | 12 | func (goo *GoProgarmmer) WriteHelloWorld() string { 13 | return "fmt.Println(\"Hello World\")" 14 | } 15 | 16 | func TestClient(t *testing.T) { 17 | var p Progarmmer 18 | p = new(GoProgarmmer) 19 | t.Log(p.WriteHelloWorld()) 20 | } 21 | -------------------------------------------------------------------------------- /src/ch12/extension/extension_test.go: -------------------------------------------------------------------------------- 1 | package extension 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type Pet struct { 9 | } 10 | 11 | func (p *Pet) Speak() { 12 | fmt.Print("...") 13 | } 14 | 15 | func (p *Pet) SpeakTo(host string) { 16 | p.Speak() 17 | fmt.Println(" ", host) 18 | } 19 | 20 | type Dog struct { 21 | p *Pet 22 | } 23 | 24 | func (d *Dog) Speak() { 25 | fmt.Print("Wang!") 26 | } 27 | 28 | func (d *Dog) SpeakTo(host string) { 29 | d.Speak() 30 | fmt.Println(" ", host) 31 | } 32 | 33 | func TestDog(t *testing.T) { 34 | dog := new(Dog) 35 | dog.SpeakTo("nikko") 36 | } 37 | -------------------------------------------------------------------------------- /src/ch13/empty_interface/empty_interface_test.go: -------------------------------------------------------------------------------- 1 | package empty_interface 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func DoSomething(p interface{}) { 9 | if i, ok := p.(int); ok { 10 | fmt.Println("Integer", i) 11 | return 12 | } 13 | if s, ok := p.(string); ok { 14 | fmt.Println("string", s) 15 | return 16 | } 17 | fmt.Println("Unknow Type") 18 | 19 | switch v := p.(type) { 20 | case int: 21 | fmt.Println("Integer", v) 22 | case string: 23 | fmt.Println("string", v) 24 | default: 25 | fmt.Println("Unknow Type") 26 | } 27 | } 28 | 29 | func TestEmptyInterfaceAssertion(t *testing.T) { 30 | DoSomething(10) 31 | DoSomething("10") 32 | } 33 | -------------------------------------------------------------------------------- /src/ch13/polymorphsim/polymorphsim_test.go: -------------------------------------------------------------------------------- 1 | package polymorphsim_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type Code string 9 | type Progarmmer interface { 10 | WriteHelloWorld() Code 11 | } 12 | 13 | type GoProgarmmer struct { 14 | } 15 | 16 | func (goo *GoProgarmmer) WriteHelloWorld() Code { 17 | return "fmt.Println(\"Hello World\")" 18 | } 19 | 20 | type JavaProgarmmer struct { 21 | } 22 | 23 | func (goo *JavaProgarmmer) WriteHelloWorld() Code { 24 | return "System.out.Println(\"Hello World\")" 25 | } 26 | 27 | func writeFirstProgram(p Progarmmer) { 28 | fmt.Printf("%T %v\n", p, p.WriteHelloWorld()) 29 | } 30 | 31 | func TestClient(t *testing.T) { 32 | goProg := new(GoProgarmmer) 33 | javaProg := new(JavaProgarmmer) 34 | writeFirstProgram(goProg) 35 | writeFirstProgram(javaProg) 36 | } 37 | -------------------------------------------------------------------------------- /src/ch14/error/error_test.go: -------------------------------------------------------------------------------- 1 | package err_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | "strconv" 7 | "testing" 8 | ) 9 | 10 | var LessThanTwoError = errors.New("n should be not less than 2") 11 | 12 | var LargerhanHundredError = errors.New("n should be not less than 2") 13 | 14 | func GetFibonacci(n int) ([]int, error) { 15 | if n < 2 { 16 | return nil, LessThanTwoError 17 | } 18 | if n > 100 { 19 | return nil, LargerhanHundredError 20 | } 21 | fibList := []int{1, 1} 22 | for i := 2; i < n; i++ { 23 | fibList = append(fibList, fibList[i-2]+fibList[i-1]) 24 | } 25 | return fibList, nil 26 | } 27 | 28 | func TestGetFibonacci(t *testing.T) { 29 | if v, err := GetFibonacci(1); err != nil { 30 | if err == LessThanTwoError { 31 | fmt.Println("It is less") 32 | } 33 | if err == LargerhanHundredError { 34 | 35 | } 36 | t.Log(err) 37 | } else { 38 | t.Log(v) 39 | } 40 | 41 | } 42 | 43 | func GetFibonacci1(str string) { 44 | var ( 45 | i int 46 | err error 47 | list []int 48 | ) 49 | if i, err = strconv.Atoi(str); err == nil { 50 | if list, err = GetFibonacci(i); err == nil { 51 | fmt.Println(list) 52 | } else { 53 | fmt.Println("Error", err) 54 | } 55 | } else { 56 | fmt.Println("Error", err) 57 | } 58 | } 59 | 60 | func GetFibonacci2(str string) { 61 | var ( 62 | i int 63 | err error 64 | list []int 65 | ) 66 | if i, err = strconv.Atoi(str); err != nil { 67 | fmt.Println("Error", err) 68 | return 69 | } 70 | 71 | if list, err = GetFibonacci(i); err != nil { 72 | fmt.Println("Error", err) 73 | return 74 | } 75 | fmt.Println(list) 76 | } 77 | -------------------------------------------------------------------------------- /src/ch14/panic_recover/panic_recover_test.go: -------------------------------------------------------------------------------- 1 | package panic_recover 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | func TestPanicVxExit(t *testing.T) { 10 | //defer func() { 11 | // fmt.Println("Finally!") 12 | //}() 13 | defer func() { 14 | if err := recover(); err != nil { 15 | fmt.Println("recovered from ", err) 16 | } 17 | }() 18 | fmt.Println("Start") 19 | panic(errors.New("Something Wrong!")) 20 | //os.Exit(-1) 21 | //fmt.Println("End") 22 | } 23 | -------------------------------------------------------------------------------- /src/ch15/client/package_test.go: -------------------------------------------------------------------------------- 1 | package client1_test 2 | 3 | import ( 4 | "ch15/series" 5 | "testing" 6 | ) 7 | 8 | func TestPackage(t *testing.T) { 9 | t.Log(series.GetFibonacci(10)) 10 | t.Log(series.Square(5)) 11 | } 12 | -------------------------------------------------------------------------------- /src/ch15/remote_package/remote_package_test.go: -------------------------------------------------------------------------------- 1 | package remote 2 | 3 | import ( 4 | cm "github.com/easierway/concurrent_map" 5 | "testing" 6 | ) 7 | 8 | func TestConcurrentMap(t *testing.T) { 9 | m := cm.CreateConcurrentMap(99) 10 | m.Set(cm.StrKey("key"), 10) 11 | t.Log(m.Get(cm.StrKey("key"))) 12 | } 13 | -------------------------------------------------------------------------------- /src/ch15/series/my_series.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import "fmt" 4 | 5 | func init() { 6 | fmt.Println("init1") 7 | } 8 | 9 | func init() { 10 | fmt.Println("init2") 11 | } 12 | 13 | func Square(n int) int { 14 | return n * n 15 | } 16 | 17 | func GetFibonacci(n int) []int { 18 | fibList := []int{1, 1} 19 | for i := 2; i < n; i++ { 20 | fibList = append(fibList, fibList[i-2]+fibList[i-1]) 21 | } 22 | return fibList 23 | } 24 | -------------------------------------------------------------------------------- /src/ch16/gorutine/groutine_test.go: -------------------------------------------------------------------------------- 1 | package gorutine 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestGroutine(t *testing.T) { 10 | for i := 0; i < 10; i++ { 11 | go func(i int) { 12 | fmt.Println(i) 13 | }(i) 14 | //go func() { 15 | // fmt.Println(i) 16 | //}() 17 | } 18 | time.Sleep(time.Millisecond * 50) 19 | } 20 | -------------------------------------------------------------------------------- /src/ch17/share_mem/share_mem_test.go: -------------------------------------------------------------------------------- 1 | package share_mem 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestCounter(t *testing.T) { 10 | counter := 0 11 | for i := 0; i < 5000; i++ { 12 | go func() { 13 | counter++ 14 | }() 15 | } 16 | time.Sleep(1 * time.Second) 17 | t.Logf("counter = %d", counter) 18 | } 19 | 20 | func TestCounterSafe(t *testing.T) { 21 | var mut sync.Mutex 22 | counter := 0 23 | for i := 0; i < 5000; i++ { 24 | go func() { 25 | defer func() { 26 | mut.Unlock() 27 | }() 28 | mut.Lock() 29 | counter++ 30 | }() 31 | } 32 | time.Sleep(1 * time.Second) 33 | t.Logf("counter = %d", counter) 34 | } 35 | 36 | func TestCounterWaitGroup(t *testing.T) { 37 | var mut sync.Mutex 38 | var wg sync.WaitGroup 39 | counter := 0 40 | for i := 0; i < 5000; i++ { 41 | wg.Add(1) 42 | go func() { 43 | defer func() { 44 | mut.Unlock() 45 | }() 46 | mut.Lock() 47 | counter++ 48 | wg.Done() 49 | }() 50 | } 51 | wg.Wait() 52 | t.Logf("counter = %d", counter) 53 | } 54 | 55 | func read(i int, m *sync.RWMutex, wg *sync.WaitGroup) { 56 | println(i, "read start") 57 | 58 | m.RLock() 59 | println(i, "reading") 60 | time.Sleep(1 * time.Second) 61 | m.RUnlock() 62 | 63 | println(i, "read over") 64 | wg.Done() 65 | } 66 | 67 | func write(i int, m *sync.RWMutex, wg *sync.WaitGroup) { 68 | println(i, "write start") 69 | 70 | m.Lock() 71 | println(i, "writing") 72 | time.Sleep(1 * time.Second) 73 | m.Unlock() 74 | 75 | println(i, "write over") 76 | wg.Done() 77 | } 78 | 79 | func TestRWMutex(t *testing.T) { 80 | var m = new(sync.RWMutex) 81 | var wg = new(sync.WaitGroup) 82 | wg.Add(5) 83 | // 写的时候啥也不能干 84 | go write(1, m, wg) 85 | go read(2, m, wg) 86 | go read(3, m, wg) 87 | go read(4, m, wg) 88 | go write(5, m, wg) 89 | 90 | wg.Wait() 91 | } 92 | -------------------------------------------------------------------------------- /src/ch18/csp/async_service_test.go: -------------------------------------------------------------------------------- 1 | package csp 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func service() string { 10 | time.Sleep(time.Millisecond * 50) 11 | return "Done" 12 | } 13 | 14 | func otherTask() { 15 | fmt.Println("working on something else") 16 | time.Sleep(time.Millisecond * 100) 17 | fmt.Println("task is done.") 18 | } 19 | 20 | func TestService(t *testing.T) { 21 | fmt.Println(service()) 22 | otherTask() 23 | } 24 | 25 | func AsyncService() chan string { 26 | retCh := make(chan string) 27 | //retCh := make(chan string,1) 28 | go func() { 29 | ret := service() 30 | fmt.Println("returned result.") 31 | retCh <- ret 32 | fmt.Println("service exited.") 33 | }() 34 | return retCh 35 | } 36 | 37 | func TestAsyncService(t *testing.T) { 38 | retCh := AsyncService() 39 | 40 | otherTask() 41 | fmt.Println(<-retCh) 42 | time.Sleep(time.Second * 1) 43 | } 44 | -------------------------------------------------------------------------------- /src/ch19/select/select_test.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func service() string { 10 | time.Sleep(time.Millisecond * 500) 11 | return "Done" 12 | } 13 | 14 | func AsyncService() chan string { 15 | retCh := make(chan string) 16 | //retCh := make(chan string,1) 17 | go func() { 18 | ret := service() 19 | fmt.Println("returned result.") 20 | retCh <- ret 21 | fmt.Println("service exited.") 22 | }() 23 | return retCh 24 | } 25 | 26 | func TestSelect(t *testing.T) { 27 | select { 28 | case ret := <-AsyncService(): 29 | t.Log(ret) 30 | case <-time.After(time.Millisecond * 100): 31 | t.Error("time out") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ch2/constant_test/constant_try_test.go: -------------------------------------------------------------------------------- 1 | package constart_test 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | const ( 8 | Monday = iota + 1 9 | Tuesday 10 | Wednesday 11 | Thursday 12 | Friday 13 | Saturday 14 | Sunday 15 | ) 16 | 17 | const ( 18 | Readable = 1 << iota //0001 19 | Writable //0010 20 | Exectable //0011 21 | ) 22 | 23 | func TestConstantTry(t *testing.T) { 24 | t.Log(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday) 25 | 26 | } 27 | 28 | func TestConstantTry1(t *testing.T) { 29 | a := 6 30 | t.Log(uint8(a), uint(Readable), uint(Writable), uint(Exectable)) 31 | c := a & Readable 32 | t.Logf("第一行 - c 的值为 %d\n", c) 33 | c = a & Writable 34 | t.Logf("第一行 - c 的值为 %d\n", c) 35 | c = a & Exectable 36 | t.Logf("第一行 - c 的值为 %d\n", c) 37 | t.Log(a&Readable == Readable, a&Writable == Writable, a&Exectable == Exectable) 38 | } 39 | -------------------------------------------------------------------------------- /src/ch2/fib/fib_test.go: -------------------------------------------------------------------------------- 1 | package fib 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestFibList(t *testing.T) { 9 | // 第一种赋值方式 10 | //var a int =1 11 | //var b int =1 12 | 13 | // 第二种赋值方式 14 | //var ( 15 | // a int = 1 16 | // b = 1 17 | //) 18 | 19 | // 第三种赋值方式 20 | a := 1 21 | b := 1 22 | fmt.Print(a) 23 | for i := 0; i < 5; i++ { 24 | fmt.Print(" ", b) 25 | tmp := a 26 | a = b 27 | b = tmp + a 28 | } 29 | fmt.Println() 30 | } 31 | 32 | func TestExchang(t *testing.T) { 33 | a := 1 34 | b := 1 35 | // 1 36 | //tmp := a 37 | //a = b 38 | //b = tmp 39 | // 40 | // 2 41 | a, b = b, a 42 | t.Log(a, b) 43 | } 44 | -------------------------------------------------------------------------------- /src/ch20/channel_close/channel_close_test.go: -------------------------------------------------------------------------------- 1 | package channel_close 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | func dataProducer(ch chan int, wg *sync.WaitGroup) { 10 | go func() { 11 | for i := 0; i < 10; i++ { 12 | ch <- i 13 | } 14 | close(ch) 15 | wg.Done() 16 | }() 17 | } 18 | 19 | func dataReceiver(ch chan int, wg *sync.WaitGroup) { 20 | go func() { 21 | for { 22 | if data, ok := <-ch; ok { 23 | fmt.Println(data) 24 | } else { 25 | break 26 | } 27 | } 28 | wg.Done() 29 | }() 30 | } 31 | 32 | func TestCloseChannel(t *testing.T) { 33 | var wg sync.WaitGroup 34 | ch := make(chan int) 35 | wg.Add(1) 36 | dataProducer(ch, &wg) 37 | wg.Add(1) 38 | dataReceiver(ch, &wg) 39 | wg.Add(1) 40 | dataReceiver(ch, &wg) 41 | wg.Wait() 42 | } 43 | -------------------------------------------------------------------------------- /src/ch20_1/cancel_by_close/cancel_test.go: -------------------------------------------------------------------------------- 1 | package cancel_by_close 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func isCancelled(cancelChan chan struct{}) bool { 10 | select { 11 | case <-cancelChan: 12 | return true 13 | default: 14 | return false 15 | } 16 | } 17 | 18 | func cancel_1(cancelChan chan struct{}) { 19 | cancelChan <- struct{}{} 20 | } 21 | 22 | func cancel_2(cancelChan chan struct{}) { 23 | close(cancelChan) 24 | } 25 | func TestCancel(t *testing.T) { 26 | cancelChan := make(chan struct{}, 0) 27 | for i := 0; i < 5; i++ { 28 | go func(i int, cancelCh chan struct{}) { 29 | for { 30 | if isCancelled(cancelCh) { 31 | break 32 | } 33 | time.Sleep(time.Millisecond * 5) 34 | } 35 | fmt.Println(i, "Cancelled") 36 | 37 | }(i, cancelChan) 38 | } 39 | cancel_2(cancelChan) 40 | time.Sleep(time.Second * 1) 41 | } 42 | -------------------------------------------------------------------------------- /src/ch20_2/cancel_by_close/cancel_test.go: -------------------------------------------------------------------------------- 1 | package cancel_by_close 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func isCancelled(ctx context.Context) bool { 11 | select { 12 | case <-ctx.Done(): 13 | return true 14 | default: 15 | return false 16 | } 17 | } 18 | 19 | func TestCancel(t *testing.T) { 20 | ctx, cancel := context.WithCancel(context.Background()) 21 | for i := 0; i < 5; i++ { 22 | go func(i int, ctx context.Context) { 23 | for { 24 | if isCancelled(ctx) { 25 | break 26 | } 27 | time.Sleep(time.Millisecond * 5) 28 | } 29 | fmt.Println(i, "Cancelled") 30 | 31 | }(i, ctx) 32 | } 33 | cancel() 34 | time.Sleep(time.Second * 1) 35 | } 36 | -------------------------------------------------------------------------------- /src/ch21/singleton/once_test.go: -------------------------------------------------------------------------------- 1 | package once_test 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | "unsafe" 8 | ) 9 | 10 | type Singleton struct { 11 | } 12 | 13 | var singleInstance *Singleton 14 | var once sync.Once 15 | 16 | func GetSingletonObj() *Singleton { 17 | once.Do(func() { 18 | fmt.Println("Create Obj") 19 | singleInstance = new(Singleton) 20 | }) 21 | return singleInstance 22 | } 23 | 24 | func TestGetSingletonObj(t *testing.T) { 25 | var wg sync.WaitGroup 26 | for i := 0; i < 10; i++ { 27 | wg.Add(1) 28 | go func() { 29 | obj := GetSingletonObj() 30 | fmt.Printf("%x\n", unsafe.Pointer(obj)) 31 | wg.Done() 32 | }() 33 | } 34 | wg.Wait() 35 | } 36 | -------------------------------------------------------------------------------- /src/ch22/util_anyone_reply/frist_response_test.go: -------------------------------------------------------------------------------- 1 | package util_anyone_reply 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func runTask(id int) string { 11 | time.Sleep(10 * time.Millisecond) 12 | return fmt.Sprintf("The result is from %d\n", id) 13 | } 14 | 15 | func FristResponse() string { 16 | numOfRunner := 10 17 | ch := make(chan string, numOfRunner) 18 | for i := 0; i < numOfRunner; i++ { 19 | go func(i int) { 20 | ret := runTask(i) 21 | ch <- ret 22 | }(i) 23 | } 24 | return <-ch 25 | } 26 | 27 | func TestFristResponse(t *testing.T) { 28 | t.Log("Before:", runtime.NumGoroutine()) 29 | t.Log(FristResponse()) 30 | time.Sleep(time.Second * 1) 31 | t.Log("After:", runtime.NumGoroutine()) 32 | } 33 | -------------------------------------------------------------------------------- /src/ch23/until_all_reply/untill_all_test.go: -------------------------------------------------------------------------------- 1 | package until_all_reply 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func runTask(id int) string { 11 | time.Sleep(10 * time.Millisecond) 12 | return fmt.Sprintf("The result is from %d\n", id) 13 | } 14 | 15 | func AllResponse() string { 16 | numOfRunner := 10 17 | ch := make(chan string, numOfRunner) 18 | for i := 0; i < numOfRunner; i++ { 19 | go func(i int) { 20 | ret := runTask(i) 21 | ch <- ret 22 | }(i) 23 | } 24 | finalRet := "" 25 | for j := 0; j < numOfRunner; j++ { 26 | finalRet += <-ch + "" 27 | } 28 | return finalRet 29 | } 30 | 31 | func TestFristResponse(t *testing.T) { 32 | t.Log("Before:", runtime.NumGoroutine()) 33 | t.Log(AllResponse()) 34 | time.Sleep(time.Second * 1) 35 | t.Log("After:", runtime.NumGoroutine()) 36 | } 37 | -------------------------------------------------------------------------------- /src/ch24/obj_pool/obj_pool.go: -------------------------------------------------------------------------------- 1 | package obj_pool 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | ) 7 | 8 | type ReusableObj struct { 9 | } 10 | 11 | type ObjPool struct { 12 | bufChan chan *ReusableObj 13 | } 14 | 15 | func NewObjPool(numOfObj int) *ObjPool { 16 | objPool := ObjPool{} 17 | objPool.bufChan = make(chan *ReusableObj, numOfObj) 18 | for i := 0; i < numOfObj; i++ { 19 | objPool.bufChan <- &ReusableObj{} 20 | } 21 | return &objPool 22 | } 23 | 24 | func (p *ObjPool) GetObj(timeout time.Duration) (*ReusableObj, error) { 25 | select { 26 | case ret := <-p.bufChan: 27 | return ret, nil 28 | case <-time.After(timeout): 29 | return nil, errors.New("timeout") 30 | 31 | } 32 | } 33 | 34 | func (p *ObjPool) ReleaseObj(obj *ReusableObj) error { 35 | select { 36 | case p.bufChan <- obj: 37 | return nil 38 | default: 39 | return errors.New("overflow") 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/ch24/obj_pool/obj_pool_test.go: -------------------------------------------------------------------------------- 1 | package obj_pool 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestObjPool(t *testing.T) { 10 | pool := NewObjPool(10) 11 | //if err := pool.ReleaseObj(&ReusableObj{}); err != nil { 12 | // t.Error(err) 13 | //} 14 | for i := 0; i < 11; i++ { 15 | if v, err := pool.GetObj(time.Second * 1); err != nil { 16 | t.Error(err) 17 | } else { 18 | fmt.Printf("%T\n", v) 19 | if err := pool.ReleaseObj(v); err != nil { 20 | t.Error(err) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ch25/obj_cache/sync_pool_test.go: -------------------------------------------------------------------------------- 1 | package obj_cache 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync" 7 | "testing" 8 | ) 9 | 10 | func TestSyncPool(t *testing.T) { 11 | pool := &sync.Pool{ 12 | New: func() interface{} { 13 | fmt.Println("Create a new object.") 14 | return 100 15 | }, 16 | } 17 | v := pool.Get().(int) 18 | fmt.Println(v) 19 | pool.Put(3) 20 | runtime.GC() 21 | v1, _ := pool.Get().(int) 22 | fmt.Println(v1) 23 | } 24 | 25 | func TestSyncPoolInMultiGroutine(t *testing.T) { 26 | pool := &sync.Pool{ 27 | New: func() interface{} { 28 | fmt.Println("Create a new object.") 29 | return 10 30 | }, 31 | } 32 | pool.Put(100) 33 | pool.Put(100) 34 | pool.Put(100) 35 | 36 | var wg sync.WaitGroup 37 | for i := 0; i < 10; i++ { 38 | wg.Add(1) 39 | go func(id int) { 40 | fmt.Println(pool.Get()) 41 | wg.Done() 42 | }(1) 43 | } 44 | wg.Wait() 45 | } 46 | -------------------------------------------------------------------------------- /src/ch3/type_test/type_test.go: -------------------------------------------------------------------------------- 1 | package type_test 2 | 3 | import "testing" 4 | 5 | type MyInt int64 6 | 7 | func TestImplicit(t *testing.T) { 8 | var a int = 1 9 | var b int64 10 | b = int64(a) 11 | 12 | var c MyInt 13 | c = MyInt(b) 14 | t.Log(a, b, c) 15 | } 16 | 17 | func TestPoint(t *testing.T) { 18 | a := 1 19 | aPtr := &a 20 | //aPtr = aPtr + 1 21 | t.Log(a, aPtr) 22 | t.Logf("%T %T", a, aPtr) 23 | } 24 | 25 | func TestString(t *testing.T) { 26 | var s string 27 | t.Log("*" + s + "*") 28 | t.Log(len(s)) 29 | if len(s) == 0 { 30 | t.Log("这是一个空字符串") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ch32/unit_test/functions.go: -------------------------------------------------------------------------------- 1 | package testing 2 | 3 | func square(op int) int { 4 | return op * op 5 | //return op*op + 1 6 | } 7 | -------------------------------------------------------------------------------- /src/ch32/unit_test/functions_test.go: -------------------------------------------------------------------------------- 1 | package testing 2 | 3 | import ( 4 | "fmt" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestSquare(t *testing.T) { 10 | inputs := [...]int{1, 2, 3} 11 | expected := [...]int{1, 4, 9} 12 | for i := 0; i < len(inputs); i++ { 13 | ret := square(inputs[i]) 14 | if ret != expected[i] { 15 | t.Errorf("input is %d, the exoected is %d, the actual %d", inputs[i], expected[i], ret) 16 | } 17 | } 18 | } 19 | 20 | func TestErrorInCode(t *testing.T) { 21 | fmt.Println("start") 22 | t.Error("Error") 23 | fmt.Println("End") 24 | } 25 | 26 | func TestFailInCode(t *testing.T) { 27 | fmt.Println("start") 28 | t.Fatal("Fail") 29 | fmt.Println("End") 30 | } 31 | 32 | func TestSquareWithAssert(t *testing.T) { 33 | inputs := [...]int{1, 2, 3} 34 | expected := [...]int{1, 4, 9} 35 | for i := 0; i < len(inputs); i++ { 36 | ret := square(inputs[i]) 37 | assert.Equal(t, expected[i], ret) 38 | if ret != expected[i] { 39 | t.Errorf("input is %d, the exoected is %d, the actual %d", inputs[i], expected[i], ret) 40 | } 41 | } 42 | } 43 | 44 | func BenchmarkConcatStringByAdd(b *testing.B) { 45 | //与性能测试无关代码 46 | b.ResetTimer() 47 | for i := 0; i < b.N; i++ { 48 | // 测试代码 49 | } 50 | b.StopTimer() 51 | //与性能测试无关代码 52 | } 53 | -------------------------------------------------------------------------------- /src/ch33/benchmark/concat_string_test.go: -------------------------------------------------------------------------------- 1 | package benchmark 2 | 3 | import ( 4 | "bytes" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestConcatStringByAdd(t *testing.T) { 10 | assert := assert.New(t) 11 | elems := []string{"1", "2", "3", "4", "5"} 12 | ret := "" 13 | for _, elem := range elems { 14 | ret += elem 15 | } 16 | assert.Equal("12345", ret) 17 | } 18 | 19 | func TestConcatStringByBytesBuffer(t *testing.T) { 20 | assert := assert.New(t) 21 | var buf bytes.Buffer 22 | elems := []string{"1", "2", "3", "4", "5"} 23 | for _, elem := range elems { 24 | buf.WriteString(elem) 25 | } 26 | assert.Equal("12345", buf.String()) 27 | } 28 | 29 | func BenchmarkConcatStringByAdd(b *testing.B) { 30 | 31 | elems := []string{"1", "2", "3", "4", "5"} 32 | b.ResetTimer() 33 | for i := 0; i < b.N; i++ { 34 | 35 | ret := "" 36 | for _, elem := range elems { 37 | ret += elem 38 | } 39 | } 40 | b.StopTimer() 41 | } 42 | 43 | func BenchmarkConcatStringByBytesBuffer(b *testing.B) { 44 | 45 | elems := []string{"1", "2", "3", "4", "5"} 46 | b.ResetTimer() 47 | var buf bytes.Buffer 48 | for i := 0; i < b.N; i++ { 49 | for _, elem := range elems { 50 | buf.WriteString(elem) 51 | } 52 | } 53 | b.StopTimer() 54 | } 55 | -------------------------------------------------------------------------------- /src/ch34/bdd/bdd_spec_test.go: -------------------------------------------------------------------------------- 1 | package bdd 2 | 3 | import ( 4 | . "github.com/smartystreets/goconvey/convey" 5 | "testing" 6 | ) 7 | 8 | func TestSpec(t *testing.T) { 9 | Convey("Given 2 even numbers", t, func() { 10 | a := 2 11 | b := 4 12 | Convey("When add the two numbers", func() { 13 | c := a + b 14 | 15 | Convey("Then the result is still even", func() { 16 | So(c%2, ShouldEqual, 0) 17 | }) 18 | }) 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /src/ch35/reflect/reflect_test.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestTypeAndValue(t *testing.T) { 10 | var f int64 = 10 11 | t.Log(reflect.TypeOf(f), reflect.ValueOf(f)) 12 | t.Log(reflect.ValueOf(f).Type()) 13 | } 14 | 15 | func CheckType(v interface{}) { 16 | t := reflect.TypeOf(v) 17 | switch t.Kind() { 18 | case reflect.Float32, reflect.Float64: 19 | fmt.Println("Float") 20 | case reflect.Int, reflect.Int32, reflect.Int64: 21 | fmt.Println("Int") 22 | default: 23 | fmt.Println("Unknow", t) 24 | } 25 | } 26 | 27 | func TestBasicType(t *testing.T) { 28 | var f float64 = 12 29 | CheckType(&f) 30 | } 31 | 32 | func TestDeepEqual(t *testing.T) { 33 | a := map[int]string{1: "one", 2: "two", 3: "three"} 34 | b := map[int]string{1: "one", 2: "two", 3: "three"} 35 | fmt.Println(reflect.DeepEqual(a, b)) 36 | 37 | s1 := []int{1, 2, 3} 38 | s2 := []int{1, 2, 3} 39 | s3 := []int{2, 3, 1} 40 | 41 | t.Log("s1==s2?", reflect.DeepEqual(s1, s2)) 42 | t.Log("s1==s2?", reflect.DeepEqual(s1, s3)) 43 | c1 := Customer{"1", "Mike", 40} 44 | c2 := Customer{"1", "Mike", 40} 45 | fmt.Println(c1 == c2) 46 | fmt.Println(reflect.DeepEqual(c1, c2)) 47 | } 48 | 49 | type Employee struct { 50 | EmployeeID string 51 | Name string `format:"normal"` 52 | Age int 53 | } 54 | 55 | func (e *Employee) UpdateAge(newVal int) { 56 | e.Age = newVal 57 | } 58 | 59 | type Customer struct { 60 | CookieID string 61 | Name string 62 | Age int 63 | } 64 | 65 | func TestInvokeByName(t *testing.T) { 66 | e := &Employee{"1", "Mike", 30} 67 | 68 | t.Logf("Name:value(%[1]v), Type(%[1]T)", reflect.ValueOf(*e).FieldByName("Name")) 69 | if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok { 70 | t.Error("Failed to get 'Name' field.") 71 | } else { 72 | t.Log("Tag:format", nameField.Tag.Get("format")) 73 | } 74 | reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(1)}) 75 | t.Log("Update Age:", e) 76 | } 77 | -------------------------------------------------------------------------------- /src/ch36/flexible_reflect_test.go: -------------------------------------------------------------------------------- 1 | package ch36 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | type Employee struct { 11 | EmployeeID string 12 | Name string `format:"normal"` 13 | Age int 14 | } 15 | 16 | type Customer struct { 17 | CookieID string 18 | Name string 19 | Age int 20 | } 21 | 22 | func TestDeepEqual(t *testing.T) { 23 | a := map[int]string{1: "one", 2: "two", 3: "three"} 24 | b := map[int]string{1: "one", 2: "two", 4: "three"} 25 | //t.Log(a == b) 26 | fmt.Println(reflect.DeepEqual(a, b)) 27 | 28 | s1 := []int{1, 2, 3} 29 | s2 := []int{1, 2, 3} 30 | s3 := []int{2, 3, 1} 31 | 32 | t.Log("s1==s2?", reflect.DeepEqual(s1, s2)) 33 | t.Log("s1==s2?", reflect.DeepEqual(s1, s3)) 34 | } 35 | 36 | func TestFillNameAnfAge(t *testing.T) { 37 | settings := map[string]interface{}{"Name": "Mike", "Age": 40} 38 | e := Employee{} 39 | if err := fillBySettings(&e, settings); err != nil { 40 | t.Fatal(err) 41 | } 42 | t.Log(e) 43 | c := new(Customer) 44 | if err := fillBySettings(c, settings); err != nil { 45 | t.Fatal(err) 46 | } 47 | t.Log(*c) 48 | } 49 | 50 | func fillBySettings(st interface{}, settings map[string]interface{}) error { 51 | if reflect.TypeOf(st).Kind() != reflect.Ptr { 52 | if reflect.TypeOf(st).Elem().Kind() != reflect.Struct { 53 | return errors.New("the first param should be a pointer to the struct type") 54 | } 55 | } 56 | 57 | if settings == nil { 58 | return errors.New("settings is nil.") 59 | } 60 | 61 | var ( 62 | field reflect.StructField 63 | ok bool 64 | ) 65 | 66 | for k, v := range settings { 67 | if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok { 68 | continue 69 | } 70 | if field.Type == reflect.TypeOf(v) { 71 | vstr := reflect.ValueOf(st) 72 | vstr = vstr.Elem() 73 | vstr.FieldByName(k).Set(reflect.ValueOf(v)) 74 | } 75 | } 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /src/ch38/unsafe_programming/unsafe_test.go: -------------------------------------------------------------------------------- 1 | package unsafe_programming 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | "testing" 8 | "time" 9 | "unsafe" 10 | ) 11 | 12 | type Customer struct { 13 | Name string 14 | Age int 15 | } 16 | 17 | func TestUnsafe(t *testing.T) { 18 | i := 10 19 | f := *(*float64)(unsafe.Pointer(&i)) 20 | t.Log(unsafe.Pointer(&i)) 21 | t.Log(f) 22 | } 23 | 24 | type MyInt int 25 | 26 | func TestConvert(t *testing.T) { 27 | a := []int{1, 2, 3, 4} 28 | b := *(*[]MyInt)(unsafe.Pointer(&a)) 29 | t.Log(b) 30 | } 31 | 32 | func TestAtomic(t *testing.T) { 33 | var shareBufPtr unsafe.Pointer 34 | writeDataFn := func() { 35 | data := []int{} 36 | for i := 0; i < 100; i++ { 37 | data = append(data, i) 38 | } 39 | atomic.StorePointer(&shareBufPtr, unsafe.Pointer(&data)) 40 | } 41 | readDataFn := func() { 42 | data := atomic.LoadPointer(&shareBufPtr) 43 | fmt.Println(data, *(*[]int)(data)) 44 | } 45 | 46 | var wg sync.WaitGroup 47 | writeDataFn() 48 | for i := 0; i < 10; i++ { 49 | wg.Add(1) 50 | go func() { 51 | for i := 0; i < 10; i++ { 52 | writeDataFn() 53 | time.Sleep(time.Microsecond * 100) 54 | } 55 | wg.Done() 56 | }() 57 | wg.Add(1) 58 | go func() { 59 | for i := 0; i < 10; i++ { 60 | readDataFn() 61 | time.Sleep(time.Microsecond * 100) 62 | } 63 | wg.Done() 64 | }() 65 | } 66 | wg.Wait() 67 | } 68 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/filter.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | type Request interface { 4 | } 5 | 6 | type Response interface { 7 | } 8 | 9 | type Filter interface { 10 | Process(data Request) (Response, error) 11 | } 12 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/split_filter.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | var SplitFilterWrongFormatError = errors.New("imput data should be string") 9 | 10 | type SplitFilter struct { 11 | delimiter string 12 | } 13 | 14 | func NewSplitFilter(delimiter string) *SplitFilter { 15 | return &SplitFilter{delimiter} 16 | } 17 | 18 | func (sf *SplitFilter) Process(data Request) (Response, error) { 19 | str, ok := data.(string) //检查输出格式/类型,是否可以处理 20 | if !ok { 21 | return nil, SplitFilterWrongFormatError 22 | } 23 | parts := strings.Split(str, sf.delimiter) 24 | return parts, nil 25 | } 26 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/split_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestStringSplit(t *testing.T) { 9 | sf := NewSplitFilter(",") 10 | resp, err := sf.Process("1,2,3") 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | parts, ok := resp.([]string) 15 | if !ok { 16 | t.Fatalf("Repsonse type is %T, but the expected type is string", parts) 17 | } 18 | if !reflect.DeepEqual(parts, []string{"1", "2", "3"}) { 19 | t.Errorf("Expected value is {\"1\",\"2\",\"3\"}, but actual is %v", parts) 20 | } 21 | } 22 | 23 | func TestWrongInput(t *testing.T) { 24 | sf := NewSplitFilter(",") 25 | _, err := sf.Process(123) 26 | if err != nil { 27 | t.Fatal("An error is expected.") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/straigt_pipeline.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | type StraightPipeline struct { 4 | Name string 5 | Filters *[]Filter 6 | } 7 | 8 | func NewStraightPipeline(name string, filters ...Filter) *StraightPipeline { 9 | return &StraightPipeline{ 10 | Name: name, 11 | Filters: &filters, 12 | } 13 | } 14 | 15 | func (f *StraightPipeline) Process(data Request) (Response, error) { 16 | var ret interface{} 17 | var err error 18 | for _, filter := range *f.Filters { 19 | ret, err = filter.Process(data) 20 | if err != nil { 21 | return ret, err 22 | } 23 | data = ret 24 | } 25 | return ret, err 26 | } 27 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/straigt_pipeline_test.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStraightPipeline(t *testing.T) { 8 | spliter := NewSplitFilter(",") 9 | converter := NewToIntFilter() 10 | sum := NewSumFilter() 11 | sp := NewStraightPipeline("p1", spliter, converter, sum) 12 | ret, err := sp.Process("1,2,3") 13 | if err != nil { 14 | t.Fatal(err) 15 | } 16 | if ret != 6 { 17 | t.Fatalf("The expected is 6, but the actual is %d", ret) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/sum_filter.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import "errors" 4 | 5 | var SumFilterWrongFormatError = errors.New("input data should be []int") 6 | 7 | type SumFilter struct { 8 | } 9 | 10 | func NewSumFilter() *SumFilter { 11 | return &SumFilter{} 12 | } 13 | 14 | func (sf *SumFilter) Process(data Request) (Response, error) { 15 | elems, ok := data.([]int) 16 | if !ok { 17 | return nil, SumFilterWrongFormatError 18 | } 19 | ret := 0 20 | for _, elem := range elems { 21 | ret += elem 22 | } 23 | return ret, nil 24 | } 25 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/sum_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import "testing" 4 | 5 | func TestSumElems(t *testing.T) { 6 | sf := NewSumFilter() 7 | ret, err := sf.Process([]int{1, 2, 3}) 8 | if err != nil { 9 | t.Fatal(err) 10 | } 11 | expected := 6 12 | if ret != expected { 13 | t.Fatalf("The expected is %d, but actual is %d", expected, ret) 14 | } 15 | } 16 | 17 | func TestWrongInputForSumFilter(t *testing.T) { 18 | sf := NewSumFilter() 19 | _, err := sf.Process([]float32{1.1, 2.2, 3.1}) 20 | 21 | if err == nil { 22 | t.Fatal("An error is expected.") 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/to_int_filter.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | ) 7 | 8 | var ToIntFilterWrongFormatError = errors.New("input data should be []string") 9 | 10 | type ToIntFilter struct { 11 | } 12 | 13 | func NewToIntFilter() *ToIntFilter { 14 | return &ToIntFilter{} 15 | } 16 | 17 | func (tif *ToIntFilter) Process(data Request) (Response, error) { 18 | parts, ok := data.([]string) 19 | if !ok { 20 | return nil, ToIntFilterWrongFormatError 21 | } 22 | ret := []int{} 23 | for _, part := range parts { 24 | s, err := strconv.Atoi(part) 25 | if err != nil { 26 | return nil, err 27 | } 28 | ret = append(ret, s) 29 | } 30 | return ret, nil 31 | } 32 | -------------------------------------------------------------------------------- /src/ch39/pipe_filter/to_int_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipe_filter 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestConvertToInt(t *testing.T) { 9 | tif := NewToIntFilter() 10 | resp, err := tif.Process([]string{"1", "2", "3"}) 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | expected := []int{1, 2, 3} 15 | if !reflect.DeepEqual(expected, resp) { 16 | t.Fatalf("The expected is %v, the actual is %v", expected, resp) 17 | } 18 | } 19 | 20 | func TestWrongInputForTIF(t *testing.T) { 21 | tif := NewToIntFilter() 22 | _, err := tif.Process([]string{"1", "2.2", "3"}) 23 | if err == nil { 24 | t.Fatal("An error is expected for wrong input") 25 | } 26 | _, err = tif.Process([]int{1, 2, 3}) 27 | if err == nil { 28 | t.Fatal("An error is expected for wrong input") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ch4/operator_test/operator_test.go: -------------------------------------------------------------------------------- 1 | package operator_test 2 | 3 | import "testing" 4 | 5 | func TestCompareArray(t *testing.T) { 6 | a := [...]int{1, 2, 3, 4} 7 | b := [...]int{1, 3, 4, 5} 8 | //c := [...]int{1, 2, 3, 4, 5} 9 | d := [...]int{1, 2, 3, 4} 10 | t.Log(a == b) 11 | //t.Log(a == c) // c长度不一样,这里直接就会报编译错误 12 | t.Log(a == d) 13 | } 14 | 15 | const ( 16 | Readable = 1 << iota //0001 17 | Writable //0010 18 | Exectable //0011 19 | ) 20 | 21 | func TestBitClear(t *testing.T) { 22 | a := 7 // 0111 23 | a = a &^ Readable 24 | a = a &^ Exectable 25 | t.Log(a&Readable == Readable, a&Writable == Writable, a&Exectable == Exectable) 26 | } 27 | -------------------------------------------------------------------------------- /src/ch40/microkernel/agent.go: -------------------------------------------------------------------------------- 1 | package microkernel 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | "sync" 9 | ) 10 | 11 | const ( 12 | Waiting = iota 13 | Running 14 | ) 15 | 16 | var WrongStateError = errors.New("can not take the operation in the current state") 17 | 18 | type CollectorsError struct { 19 | CollectorErrors []error 20 | } 21 | 22 | func (ce CollectorsError) Error() string { 23 | var strs []string 24 | for _, err := range ce.CollectorErrors { 25 | strs = append(strs, err.Error()) 26 | } 27 | return strings.Join(strs, ";") 28 | } 29 | 30 | type Event struct { 31 | Source string 32 | Content string 33 | } 34 | 35 | type EventReceiver interface { 36 | OnEvent(evt Event) 37 | } 38 | 39 | type Collector interface { 40 | Init(evtReceiver EventReceiver) error 41 | Start(agtCtx context.Context) error 42 | Stop() error 43 | Destory() error 44 | } 45 | 46 | type Agent struct { 47 | collectors map[string]Collector 48 | evtBuf chan Event 49 | cancel context.CancelFunc 50 | ctx context.Context 51 | state int 52 | } 53 | 54 | func (agt *Agent) EventProcessGroutine() { 55 | var evtSeg [10]Event 56 | for { 57 | for i := 0; i < 10; i++ { 58 | select { 59 | case evtSeg[i] = <-agt.evtBuf: 60 | case <-agt.ctx.Done(): 61 | return 62 | } 63 | } 64 | fmt.Println(evtSeg) 65 | } 66 | 67 | } 68 | 69 | func NewAgent(sizeEvtBuf int) *Agent { 70 | agt := Agent{ 71 | collectors: map[string]Collector{}, 72 | evtBuf: make(chan Event, sizeEvtBuf), 73 | state: Waiting, 74 | } 75 | 76 | return &agt 77 | } 78 | 79 | func (agt *Agent) RegisterCollector(name string, collector Collector) error { 80 | if agt.state != Waiting { 81 | return WrongStateError 82 | } 83 | agt.collectors[name] = collector 84 | return collector.Init(agt) 85 | } 86 | 87 | func (agt *Agent) startCollectors() error { 88 | var err error 89 | var errs CollectorsError 90 | var mutex sync.Mutex 91 | 92 | for name, collector := range agt.collectors { 93 | go func(name string, collector Collector, ctx context.Context) { 94 | defer func() { 95 | mutex.Unlock() 96 | }() 97 | err = collector.Start(ctx) 98 | mutex.Lock() 99 | if err != nil { 100 | errs.CollectorErrors = append(errs.CollectorErrors, 101 | errors.New(name+":"+err.Error())) 102 | } 103 | }(name, collector, agt.ctx) 104 | } 105 | if len(errs.CollectorErrors) == 0 { 106 | return nil 107 | } 108 | return errs 109 | } 110 | 111 | func (agt *Agent) stopCollectors() error { 112 | var err error 113 | var errs CollectorsError 114 | for name, collector := range agt.collectors { 115 | if err = collector.Stop(); err != nil { 116 | errs.CollectorErrors = append(errs.CollectorErrors, 117 | errors.New(name+":"+err.Error())) 118 | } 119 | } 120 | if len(errs.CollectorErrors) == 0 { 121 | return nil 122 | } 123 | 124 | return errs 125 | } 126 | 127 | func (agt *Agent) destoryCollectors() error { 128 | var err error 129 | var errs CollectorsError 130 | for name, collector := range agt.collectors { 131 | if err = collector.Destory(); err != nil { 132 | errs.CollectorErrors = append(errs.CollectorErrors, 133 | errors.New(name+":"+err.Error())) 134 | } 135 | } 136 | if len(errs.CollectorErrors) == 0 { 137 | return nil 138 | } 139 | return errs 140 | } 141 | 142 | func (agt *Agent) Start() error { 143 | if agt.state != Waiting { 144 | return WrongStateError 145 | } 146 | agt.state = Running 147 | agt.ctx, agt.cancel = context.WithCancel(context.Background()) 148 | go agt.EventProcessGroutine() 149 | return agt.startCollectors() 150 | } 151 | 152 | func (agt *Agent) Stop() error { 153 | if agt.state != Running { 154 | return WrongStateError 155 | } 156 | agt.state = Waiting 157 | agt.cancel() 158 | return agt.stopCollectors() 159 | } 160 | 161 | func (agt *Agent) Destory() error { 162 | if agt.state != Waiting { 163 | return WrongStateError 164 | } 165 | return agt.destoryCollectors() 166 | } 167 | 168 | func (agt *Agent) OnEvent(evt Event) { 169 | agt.evtBuf <- evt 170 | } 171 | -------------------------------------------------------------------------------- /src/ch40/microkernel/agent_test.go: -------------------------------------------------------------------------------- 1 | package microkernel 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | type DemoCollector struct { 12 | evtReceiver EventReceiver 13 | agtCtx context.Context 14 | stopChan chan struct{} 15 | name string 16 | content string 17 | } 18 | 19 | func NewCollect(name string, content string) *DemoCollector { 20 | return &DemoCollector{ 21 | stopChan: make(chan struct{}), 22 | name: name, 23 | content: content, 24 | } 25 | } 26 | 27 | func (c *DemoCollector) Init(evtReceiver EventReceiver) error { 28 | fmt.Println("initialize collector", c.name) 29 | c.evtReceiver = evtReceiver 30 | return nil 31 | } 32 | 33 | func (c *DemoCollector) Start(agtCtx context.Context) error { 34 | fmt.Println("start collector", c.name) 35 | for { 36 | select { 37 | case <-agtCtx.Done(): 38 | c.stopChan <- struct{}{} 39 | break 40 | default: 41 | time.Sleep(time.Millisecond * 50) 42 | c.evtReceiver.OnEvent(Event{c.name, c.content}) 43 | } 44 | } 45 | } 46 | 47 | func (c *DemoCollector) Stop() error { 48 | fmt.Println("stop collector", c.name) 49 | select { 50 | case <-c.stopChan: 51 | return nil 52 | case <-time.After(time.Second * 1): 53 | return errors.New("failed to stop for timeout") 54 | } 55 | } 56 | 57 | func (c *DemoCollector) Destory() error { 58 | fmt.Println(c.name, "released resources.") 59 | return nil 60 | } 61 | 62 | func TestAgent(t *testing.T) { 63 | agt := NewAgent(100) 64 | c1 := NewCollect("c1", "1") 65 | c2 := NewCollect("c2", "2") 66 | agt.RegisterCollector("c1", c1) 67 | agt.RegisterCollector("c2", c2) 68 | if err := agt.Start(); err != nil { 69 | fmt.Printf("start error %v\n", err) 70 | } 71 | fmt.Println(agt.Start()) 72 | time.Sleep(time.Second * 1) 73 | agt.Stop() 74 | agt.Destory() 75 | } 76 | -------------------------------------------------------------------------------- /src/ch41/json/embedded_json_test.go: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | var jsonStr = `{ 10 | "basic_info":{ 11 | "name":"Mike", 12 | "age":30 13 | }, 14 | "job_info":{ 15 | "skills":["Java","Go","C"] 16 | } 17 | } ` 18 | 19 | func TestEmbeddedJson(t *testing.T) { 20 | e := new(Employee) 21 | err := json.Unmarshal([]byte(jsonStr), e) 22 | if err != nil { 23 | t.Error(err) 24 | } 25 | fmt.Println(*e) 26 | if v, err := json.Marshal(e); err == nil { 27 | fmt.Println(string(v)) 28 | } else { 29 | t.Error(err) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/ch41/json/struct_def.go: -------------------------------------------------------------------------------- 1 | package json 2 | 3 | type BasicInfo struct { 4 | Name string `json:"name"` 5 | Age int `json:"age"` 6 | } 7 | type JobInfo struct { 8 | Skills []string `json:"skills"` 9 | } 10 | type Employee struct { 11 | BasicInfo BasicInfo `json:"basic_info"` 12 | JobInfo JobInfo `json:"job_info"` 13 | } 14 | -------------------------------------------------------------------------------- /src/ch42/easyjson/embedded_json_test.go: -------------------------------------------------------------------------------- 1 | package easyjson 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | ) 8 | 9 | var jsonStr = `{ 10 | "basic_info":{ 11 | "name":"Mike", 12 | "age":30 13 | }, 14 | "job_info":{ 15 | "skills":["Java","Go","C"] 16 | } 17 | } ` 18 | 19 | func TestEmbeddedJson(t *testing.T) { 20 | e := new(Employee) 21 | err := json.Unmarshal([]byte(jsonStr), e) 22 | if err != nil { 23 | t.Error(err) 24 | } 25 | fmt.Println(*e) 26 | if v, err := json.Marshal(e); err == nil { 27 | fmt.Println(string(v)) 28 | } else { 29 | t.Error(err) 30 | } 31 | 32 | } 33 | 34 | func TestEasyJson(t *testing.T) { 35 | e := Employee{} 36 | e.UnmarshalJSON([]byte(jsonStr)) 37 | fmt.Println(e) 38 | if v, err := e.MarshalJSON(); err != nil { 39 | t.Error(err) 40 | } else { 41 | fmt.Println(string(v)) 42 | } 43 | } 44 | 45 | func BenchmarkEmbeddedJson(b *testing.B) { 46 | b.ResetTimer() 47 | e := new(Employee) 48 | for i := 0; i < b.N; i++ { 49 | 50 | err := json.Unmarshal([]byte(jsonStr), e) 51 | if err != nil { 52 | b.Error(err) 53 | } 54 | if _, err = json.Marshal(e); err != nil { 55 | b.Error(err) 56 | } 57 | } 58 | } 59 | 60 | func BenchmarkEasyJson(b *testing.B) { 61 | b.ResetTimer() 62 | e := Employee{} 63 | for i := 0; i < b.N; i++ { 64 | err := e.UnmarshalJSON([]byte(jsonStr)) 65 | if err != nil { 66 | b.Error(err) 67 | } 68 | if _, err = e.MarshalJSON(); err != nil { 69 | b.Error(err) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/ch42/easyjson/struct_def.go: -------------------------------------------------------------------------------- 1 | package easyjson 2 | 3 | type BasicInfo struct { 4 | Name string `json:"name"` 5 | Age int `json:"age"` 6 | } 7 | type JobInfo struct { 8 | Skills []string `json:"skills"` 9 | } 10 | type Employee struct { 11 | BasicInfo BasicInfo `json:"basic_info"` 12 | JobInfo JobInfo `json:"job_info"` 13 | } 14 | -------------------------------------------------------------------------------- /src/ch42/easyjson/struct_def_easyjson.go: -------------------------------------------------------------------------------- 1 | package easyjson 2 | 3 | import ( 4 | json "encoding/json" 5 | easyjson "github.com/mailru/easyjson" 6 | jlexer "github.com/mailru/easyjson/jlexer" 7 | jwriter "github.com/mailru/easyjson/jwriter" 8 | ) 9 | 10 | // suppress unused package warning 11 | var ( 12 | _ *json.RawMessage 13 | _ *jlexer.Lexer 14 | _ *jwriter.Writer 15 | _ easyjson.Marshaler 16 | ) 17 | 18 | func easyjson7c82d03DecodeCh42Easyjson(in *jlexer.Lexer, out *JobInfo) { 19 | isTopLevel := in.IsStart() 20 | if in.IsNull() { 21 | if isTopLevel { 22 | in.Consumed() 23 | } 24 | in.Skip() 25 | return 26 | } 27 | in.Delim('{') 28 | for !in.IsDelim('}') { 29 | key := in.UnsafeString() 30 | in.WantColon() 31 | if in.IsNull() { 32 | in.Skip() 33 | in.WantComma() 34 | continue 35 | } 36 | switch key { 37 | case "skills": 38 | if in.IsNull() { 39 | in.Skip() 40 | out.Skills = nil 41 | } else { 42 | in.Delim('[') 43 | if out.Skills == nil { 44 | if !in.IsDelim(']') { 45 | out.Skills = make([]string, 0, 4) 46 | } else { 47 | out.Skills = []string{} 48 | } 49 | } else { 50 | out.Skills = (out.Skills)[:0] 51 | } 52 | for !in.IsDelim(']') { 53 | var v1 string 54 | v1 = string(in.String()) 55 | out.Skills = append(out.Skills, v1) 56 | in.WantComma() 57 | } 58 | in.Delim(']') 59 | } 60 | default: 61 | in.SkipRecursive() 62 | } 63 | in.WantComma() 64 | } 65 | in.Delim('}') 66 | if isTopLevel { 67 | in.Consumed() 68 | } 69 | } 70 | func easyjson7c82d03EncodeCh42Easyjson(out *jwriter.Writer, in JobInfo) { 71 | out.RawByte('{') 72 | first := true 73 | _ = first 74 | { 75 | const prefix string = ",\"skills\":" 76 | if first { 77 | first = false 78 | out.RawString(prefix[1:]) 79 | } else { 80 | out.RawString(prefix) 81 | } 82 | if in.Skills == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { 83 | out.RawString("null") 84 | } else { 85 | out.RawByte('[') 86 | for v2, v3 := range in.Skills { 87 | if v2 > 0 { 88 | out.RawByte(',') 89 | } 90 | out.String(string(v3)) 91 | } 92 | out.RawByte(']') 93 | } 94 | } 95 | out.RawByte('}') 96 | } 97 | 98 | // MarshalJSON supports json.Marshaler interface 99 | func (v JobInfo) MarshalJSON() ([]byte, error) { 100 | w := jwriter.Writer{} 101 | easyjson7c82d03EncodeCh42Easyjson(&w, v) 102 | return w.Buffer.BuildBytes(), w.Error 103 | } 104 | 105 | // MarshalEasyJSON supports easyjson.Marshaler interface 106 | func (v JobInfo) MarshalEasyJSON(w *jwriter.Writer) { 107 | easyjson7c82d03EncodeCh42Easyjson(w, v) 108 | } 109 | 110 | // UnmarshalJSON supports json.Unmarshaler interface 111 | func (v *JobInfo) UnmarshalJSON(data []byte) error { 112 | r := jlexer.Lexer{Data: data} 113 | easyjson7c82d03DecodeCh42Easyjson(&r, v) 114 | return r.Error() 115 | } 116 | 117 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 118 | func (v *JobInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { 119 | easyjson7c82d03DecodeCh42Easyjson(l, v) 120 | } 121 | func easyjson7c82d03DecodeCh42Easyjson1(in *jlexer.Lexer, out *Employee) { 122 | isTopLevel := in.IsStart() 123 | if in.IsNull() { 124 | if isTopLevel { 125 | in.Consumed() 126 | } 127 | in.Skip() 128 | return 129 | } 130 | in.Delim('{') 131 | for !in.IsDelim('}') { 132 | key := in.UnsafeString() 133 | in.WantColon() 134 | if in.IsNull() { 135 | in.Skip() 136 | in.WantComma() 137 | continue 138 | } 139 | switch key { 140 | case "basic_info": 141 | (out.BasicInfo).UnmarshalEasyJSON(in) 142 | case "job_info": 143 | (out.JobInfo).UnmarshalEasyJSON(in) 144 | default: 145 | in.SkipRecursive() 146 | } 147 | in.WantComma() 148 | } 149 | in.Delim('}') 150 | if isTopLevel { 151 | in.Consumed() 152 | } 153 | } 154 | func easyjson7c82d03EncodeCh42Easyjson1(out *jwriter.Writer, in Employee) { 155 | out.RawByte('{') 156 | first := true 157 | _ = first 158 | { 159 | const prefix string = ",\"basic_info\":" 160 | if first { 161 | first = false 162 | out.RawString(prefix[1:]) 163 | } else { 164 | out.RawString(prefix) 165 | } 166 | (in.BasicInfo).MarshalEasyJSON(out) 167 | } 168 | { 169 | const prefix string = ",\"job_info\":" 170 | if first { 171 | first = false 172 | out.RawString(prefix[1:]) 173 | } else { 174 | out.RawString(prefix) 175 | } 176 | (in.JobInfo).MarshalEasyJSON(out) 177 | } 178 | out.RawByte('}') 179 | } 180 | 181 | // MarshalJSON supports json.Marshaler interface 182 | func (v Employee) MarshalJSON() ([]byte, error) { 183 | w := jwriter.Writer{} 184 | easyjson7c82d03EncodeCh42Easyjson1(&w, v) 185 | return w.Buffer.BuildBytes(), w.Error 186 | } 187 | 188 | // MarshalEasyJSON supports easyjson.Marshaler interface 189 | func (v Employee) MarshalEasyJSON(w *jwriter.Writer) { 190 | easyjson7c82d03EncodeCh42Easyjson1(w, v) 191 | } 192 | 193 | // UnmarshalJSON supports json.Unmarshaler interface 194 | func (v *Employee) UnmarshalJSON(data []byte) error { 195 | r := jlexer.Lexer{Data: data} 196 | easyjson7c82d03DecodeCh42Easyjson1(&r, v) 197 | return r.Error() 198 | } 199 | 200 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 201 | func (v *Employee) UnmarshalEasyJSON(l *jlexer.Lexer) { 202 | easyjson7c82d03DecodeCh42Easyjson1(l, v) 203 | } 204 | func easyjson7c82d03DecodeCh42Easyjson2(in *jlexer.Lexer, out *BasicInfo) { 205 | isTopLevel := in.IsStart() 206 | if in.IsNull() { 207 | if isTopLevel { 208 | in.Consumed() 209 | } 210 | in.Skip() 211 | return 212 | } 213 | in.Delim('{') 214 | for !in.IsDelim('}') { 215 | key := in.UnsafeString() 216 | in.WantColon() 217 | if in.IsNull() { 218 | in.Skip() 219 | in.WantComma() 220 | continue 221 | } 222 | switch key { 223 | case "name": 224 | out.Name = string(in.String()) 225 | case "age": 226 | out.Age = int(in.Int()) 227 | default: 228 | in.SkipRecursive() 229 | } 230 | in.WantComma() 231 | } 232 | in.Delim('}') 233 | if isTopLevel { 234 | in.Consumed() 235 | } 236 | } 237 | func easyjson7c82d03EncodeCh42Easyjson2(out *jwriter.Writer, in BasicInfo) { 238 | out.RawByte('{') 239 | first := true 240 | _ = first 241 | { 242 | const prefix string = ",\"name\":" 243 | if first { 244 | first = false 245 | out.RawString(prefix[1:]) 246 | } else { 247 | out.RawString(prefix) 248 | } 249 | out.String(string(in.Name)) 250 | } 251 | { 252 | const prefix string = ",\"age\":" 253 | if first { 254 | first = false 255 | out.RawString(prefix[1:]) 256 | } else { 257 | out.RawString(prefix) 258 | } 259 | out.Int(int(in.Age)) 260 | } 261 | out.RawByte('}') 262 | } 263 | 264 | // MarshalJSON supports json.Marshaler interface 265 | func (v BasicInfo) MarshalJSON() ([]byte, error) { 266 | w := jwriter.Writer{} 267 | easyjson7c82d03EncodeCh42Easyjson2(&w, v) 268 | return w.Buffer.BuildBytes(), w.Error 269 | } 270 | 271 | // MarshalEasyJSON supports easyjson.Marshaler interface 272 | func (v BasicInfo) MarshalEasyJSON(w *jwriter.Writer) { 273 | easyjson7c82d03EncodeCh42Easyjson2(w, v) 274 | } 275 | 276 | // UnmarshalJSON supports json.Unmarshaler interface 277 | func (v *BasicInfo) UnmarshalJSON(data []byte) error { 278 | r := jlexer.Lexer{Data: data} 279 | easyjson7c82d03DecodeCh42Easyjson2(&r, v) 280 | return r.Error() 281 | } 282 | 283 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 284 | func (v *BasicInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { 285 | easyjson7c82d03DecodeCh42Easyjson2(l, v) 286 | } 287 | -------------------------------------------------------------------------------- /src/ch43/hello_http/hello_http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/julienschmidt/httprouter" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 11 | fmt.Fprint(w, "welcome!\n") 12 | } 13 | 14 | func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 15 | fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) 16 | } 17 | 18 | func main() { 19 | router := httprouter.New() 20 | router.GET("/", Index) 21 | router.GET("/hello/:name", Hello) 22 | 23 | log.Fatal(http.ListenAndServe(":8090", router)) 24 | } 25 | 26 | //func main() { 27 | // http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { 28 | // fmt.Fprintf(writer, "Hello World!") 29 | // }) 30 | // 31 | // http.HandleFunc("/time", func(writer http.ResponseWriter, request *http.Request) { 32 | // t := time.Now() 33 | // timerStr := fmt.Sprintf("{\"time\":\"%s\"}", t) 34 | // writer.Write([]byte(timerStr)) 35 | // }) 36 | // 37 | // http.ListenAndServe(":8090", nil) 38 | //} 39 | -------------------------------------------------------------------------------- /src/ch43/roa/resource_oriented_arc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | 9 | "github.com/julienschmidt/httprouter" 10 | ) 11 | 12 | type Employee struct { 13 | ID string `json:"id"` 14 | Name string `json:"name"` 15 | Age int `json:"age"` 16 | } 17 | 18 | var employeeDB map[string]*Employee 19 | 20 | func init() { 21 | employeeDB = map[string]*Employee{} 22 | employeeDB["Mike"] = &Employee{"e-1", "Mike", 35} 23 | employeeDB["Rose"] = &Employee{"e-2", "Rose", 45} 24 | } 25 | 26 | func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 27 | fmt.Fprint(w, "Welcome!\n") 28 | } 29 | 30 | func GetEmployeeByName(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 31 | qName := ps.ByName("name") 32 | var ( 33 | ok bool 34 | info *Employee 35 | infoJson []byte 36 | err error 37 | ) 38 | if info, ok = employeeDB[qName]; !ok { 39 | w.Write([]byte("{\"error\":\"Not Found\"}")) 40 | return 41 | } 42 | if infoJson, err = json.Marshal(info); err != nil { 43 | w.Write([]byte(fmt.Sprintf("{\"error\":,\"%s\"}", err))) 44 | return 45 | } 46 | 47 | w.Write(infoJson) 48 | } 49 | 50 | func main() { 51 | router := httprouter.New() 52 | router.GET("/", Index) 53 | router.GET("/employee/:name", GetEmployeeByName) 54 | 55 | log.Fatal(http.ListenAndServe(":8080", router)) 56 | } 57 | -------------------------------------------------------------------------------- /src/ch44/tools/file/cpuporf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch44/tools/file/cpuporf.png -------------------------------------------------------------------------------- /src/ch44/tools/file/prof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "math/rand" 6 | "os" 7 | "runtime/pprof" 8 | "time" 9 | ) 10 | 11 | const ( 12 | col = 10000 13 | row = 10000 14 | ) 15 | 16 | func fillMatrix(m *[row][col]int) { 17 | s := rand.New(rand.NewSource(time.Now().UnixNano())) 18 | 19 | for i := 0; i < row; i++ { 20 | for j := 0; j < col; j++ { 21 | m[i][j] = s.Intn(100000) 22 | } 23 | } 24 | } 25 | 26 | func calculate(m *[row][col]int) { 27 | for i := 0; i < row; i++ { 28 | tmp := 0 29 | for j := 0; j < col; j++ { 30 | tmp += m[i][j] 31 | } 32 | } 33 | } 34 | 35 | func main() { 36 | //创建输出文件 37 | f, err := os.Create("cpu.prof") 38 | if err != nil { 39 | log.Fatal("could not create CPU profile: ", err) 40 | } 41 | 42 | // 获取系统信息 43 | if err := pprof.StartCPUProfile(f); err != nil { //监控cpu 44 | log.Fatal("could not start CPU profile: ", err) 45 | } 46 | defer pprof.StopCPUProfile() 47 | 48 | // 主逻辑区,进行一些简单的代码运算 49 | x := [row][col]int{} 50 | fillMatrix(&x) 51 | calculate(&x) 52 | 53 | f1, err := os.Create("mem.prof") 54 | if err != nil { 55 | log.Fatal("could not create memory profile: ", err) 56 | } 57 | //runtime.GC() // GC,获取最新的数据信息 58 | if err := pprof.WriteHeapProfile(f1); err != nil { // 写入内存信息 59 | log.Fatal("could not write memory profile: ", err) 60 | } 61 | f1.Close() 62 | 63 | f2, err := os.Create("goroutine.prof") 64 | if err != nil { 65 | log.Fatal("could not create groutine profile: ", err) 66 | } 67 | 68 | if gProf := pprof.Lookup("goroutine"); gProf == nil { 69 | log.Fatal("could not write groutine profile: ") 70 | } else { 71 | gProf.WriteTo(f2, 0) 72 | } 73 | f2.Close() 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/ch44/tools/http/fb_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | _ "net/http/pprof" 8 | ) 9 | 10 | func GetFibonacciSerie(n int) []int { 11 | ret := make([]int, 2, n) 12 | ret[0] = 1 13 | ret[1] = 1 14 | for i := 2; i < n; i++ { 15 | ret = append(ret, ret[i-2]+ret[i-1]) 16 | } 17 | return ret 18 | } 19 | 20 | func index(w http.ResponseWriter, r *http.Request) { 21 | w.Write([]byte("Welcome!")) 22 | } 23 | 24 | func createFBS(w http.ResponseWriter, r *http.Request) { 25 | var fbs []int 26 | for i := 0; i < 1000000; i++ { 27 | fbs = GetFibonacciSerie(50) 28 | } 29 | w.Write([]byte(fmt.Sprintf("%v", fbs))) 30 | 31 | } 32 | 33 | func main() { 34 | http.HandleFunc("/", index) 35 | http.HandleFunc("/fb", createFBS) 36 | log.Fatal(http.ListenAndServe(":8081", nil)) 37 | } 38 | -------------------------------------------------------------------------------- /src/ch45/easyjsonls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/easyjsonls.png -------------------------------------------------------------------------------- /src/ch45/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/list.png -------------------------------------------------------------------------------- /src/ch45/ls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/ls.png -------------------------------------------------------------------------------- /src/ch45/optimization_test.go: -------------------------------------------------------------------------------- 1 | package profiling 2 | 3 | import "testing" 4 | 5 | func TestCreateRequest(t *testing.T) { 6 | str := createRequest() 7 | t.Log(str) 8 | } 9 | 10 | func TestProcessRequest(t *testing.T) { 11 | reqs := []string{} 12 | reqs = append(reqs, createRequest()) 13 | reps := processRequest(reqs) 14 | t.Log(reps[0]) 15 | } 16 | 17 | func BenchmarkProcessRequests(b *testing.B) { 18 | 19 | reqs := []string{} 20 | reqs = append(reqs, createRequest()) 21 | b.ResetTimer() 22 | for i := 0; i < b.N; i++ { 23 | _ = processRequest(reqs) 24 | } 25 | b.StopTimer() 26 | 27 | } 28 | 29 | //func BenchmarkProcessRequestOld(b *testing.B) { 30 | // 31 | // reqs := []string{} 32 | // reqs = append(reqs, createRequest()) 33 | // b.ResetTimer() 34 | // for i := 0; i < b.N; i++ { 35 | // _ = processRequestOld(reqs) 36 | // } 37 | // b.StopTimer() 38 | // 39 | //} 40 | -------------------------------------------------------------------------------- /src/ch45/optmization.go: -------------------------------------------------------------------------------- 1 | package profiling 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | ) 7 | 8 | func createRequest() string { 9 | payload := make([]int, 100, 100) 10 | for i := 0; i < 100; i++ { 11 | payload[i] = i 12 | } 13 | req := Request{"demo_transaction", payload} 14 | v, err := json.Marshal(&req) 15 | if err != nil { 16 | panic(err) 17 | } 18 | return string(v) 19 | } 20 | 21 | func processRequest(reqs []string) []string { 22 | reps := []string{} 23 | for _, req := range reqs { 24 | reqObj := &Request{} 25 | reqObj.UnmarshalJSON([]byte(req)) 26 | 27 | ret := "" 28 | for _, e := range reqObj.PayLoad { 29 | ret += strconv.Itoa(e) + "," 30 | } 31 | repObj := &Response{reqObj.TransactionID, ret} 32 | repJson, err := repObj.MarshalJSON() 33 | if err != nil { 34 | panic(err) 35 | } 36 | reps = append(reps, string(repJson)) 37 | } 38 | return reps 39 | } 40 | 41 | //func processRequest(reqs []string) []string { 42 | // reps := []string{} 43 | // for _, req := range reqs { 44 | // reqObj := &Request{} 45 | // json.Unmarshal([]byte(req), reqObj) 46 | // ret := "" 47 | // for _, e := range reqObj.PayLoad { 48 | // ret += strconv.Itoa(e) + "," 49 | // } 50 | // repObj := &Response{reqObj.TransactionID, ret} 51 | // repJson, err := json.Marshal(&repObj) 52 | // if err != nil { 53 | // panic(err) 54 | // } 55 | // reps = append(reps, string(repJson)) 56 | // } 57 | // return reps 58 | //} 59 | -------------------------------------------------------------------------------- /src/ch45/structs.go: -------------------------------------------------------------------------------- 1 | package profiling 2 | 3 | type Request struct { 4 | TransactionID string `json:"transaction_id"` 5 | PayLoad []int `json:"payload"` 6 | } 7 | 8 | type Response struct { 9 | TransactionID string `json:"transaction_id"` 10 | Expression string `json:"exp"` 11 | } 12 | -------------------------------------------------------------------------------- /src/ch45/top-cum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/top-cum.png -------------------------------------------------------------------------------- /src/ch45/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/top.png -------------------------------------------------------------------------------- /src/ch45/yhbench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/yhbench.png -------------------------------------------------------------------------------- /src/ch45/yhcreatecpuprof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch45/yhcreatecpuprof.png -------------------------------------------------------------------------------- /src/ch46/lock/lock_test.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | var cache map[string]string 10 | 11 | const NUM_OF_READER int = 40 12 | const READ_TIMES = 100000 13 | 14 | func init() { 15 | cache = make(map[string]string) 16 | 17 | cache["a"] = "aa" 18 | cache["b"] = "bb" 19 | } 20 | 21 | func lockFreeAccess() { 22 | 23 | var wg sync.WaitGroup 24 | wg.Add(NUM_OF_READER) 25 | for i := 0; i < NUM_OF_READER; i++ { 26 | go func() { 27 | for j := 0; j < READ_TIMES; j++ { 28 | _, err := cache["a"] 29 | if !err { 30 | fmt.Println("Nothing") 31 | } 32 | } 33 | wg.Done() 34 | }() 35 | } 36 | wg.Wait() 37 | } 38 | 39 | func lockAccess() { 40 | 41 | var wg sync.WaitGroup 42 | wg.Add(NUM_OF_READER) 43 | m := new(sync.RWMutex) 44 | for i := 0; i < NUM_OF_READER; i++ { 45 | go func() { 46 | for j := 0; j < READ_TIMES; j++ { 47 | 48 | m.RLock() 49 | _, err := cache["a"] 50 | if !err { 51 | fmt.Println("Nothing") 52 | } 53 | m.RUnlock() 54 | } 55 | wg.Done() 56 | }() 57 | } 58 | wg.Wait() 59 | } 60 | 61 | func BenchmarkLockFree(b *testing.B) { 62 | b.ResetTimer() 63 | for i := 0; i < b.N; i++ { 64 | lockFreeAccess() 65 | } 66 | } 67 | 68 | func BenchmarkLock(b *testing.B) { 69 | b.ResetTimer() 70 | for i := 0; i < b.N; i++ { 71 | lockAccess() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/ch46/maps/concurrent_map_benchmark_adapter.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "github.com/easierway/concurrent_map" 4 | 5 | type ConcurrentMapBenchmarkAdapter struct { 6 | cm *concurrent_map.ConcurrentMap 7 | } 8 | 9 | func (m *ConcurrentMapBenchmarkAdapter) Set(key interface{}, value interface{}) { 10 | m.cm.Set(concurrent_map.StrKey(key.(string)), value) 11 | } 12 | 13 | func (m *ConcurrentMapBenchmarkAdapter) Get(key interface{}) (interface{}, bool) { 14 | return m.cm.Get(concurrent_map.StrKey(key.(string))) 15 | } 16 | 17 | func (m *ConcurrentMapBenchmarkAdapter) Del(key interface{}) { 18 | m.cm.Del(concurrent_map.StrKey(key.(string))) 19 | } 20 | 21 | func CreateConcurrentMapBenchmarkAdapter(numOfPartitions int) *ConcurrentMapBenchmarkAdapter { 22 | conMap := concurrent_map.CreateConcurrentMap(numOfPartitions) 23 | return &ConcurrentMapBenchmarkAdapter{conMap} 24 | } 25 | -------------------------------------------------------------------------------- /src/ch46/maps/map_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import ( 4 | "strconv" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | const ( 10 | NumOfReader = 10 11 | NumOfWriter = 1 12 | ) 13 | 14 | type Map interface { 15 | Set(key interface{}, val interface{}) 16 | Get(key interface{}) (interface{}, bool) 17 | Del(key interface{}) 18 | } 19 | 20 | func benchmarkMap(b *testing.B, hm Map) { 21 | for i := 0; i < b.N; i++ { 22 | var wg sync.WaitGroup 23 | for i := 0; i < NumOfWriter; i++ { 24 | wg.Add(1) 25 | go func() { 26 | for i := 0; i < 100; i++ { 27 | hm.Set(strconv.Itoa(i), i*i) 28 | hm.Set(strconv.Itoa(i), i*i) 29 | hm.Del(strconv.Itoa(i)) 30 | } 31 | wg.Done() 32 | }() 33 | } 34 | for i := 0; i < NumOfReader; i++ { 35 | wg.Add(1) 36 | go func() { 37 | for i := 0; i < 100; i++ { 38 | hm.Get(strconv.Itoa(i)) 39 | } 40 | wg.Done() 41 | }() 42 | } 43 | wg.Wait() 44 | } 45 | } 46 | 47 | func BenchmarkSyncmap(b *testing.B) { 48 | b.Run("map with RWLock", func(b *testing.B) { 49 | hm := CreateRWLockMap() 50 | benchmarkMap(b, hm) 51 | }) 52 | 53 | b.Run("sync.map", func(b *testing.B) { 54 | hm := CreateSyncMapBenchmarkAdapter() 55 | benchmarkMap(b, hm) 56 | }) 57 | 58 | b.Run("concurrent map", func(b *testing.B) { 59 | superman := CreateConcurrentMapBenchmarkAdapter(199) 60 | benchmarkMap(b, superman) 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /src/ch46/maps/rw_map.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "sync" 4 | 5 | type RWLockMap struct { 6 | m map[interface{}]interface{} 7 | lock sync.RWMutex 8 | } 9 | 10 | func (m *RWLockMap) Get(key interface{}) (interface{}, bool) { 11 | m.lock.RLock() 12 | v, ok := m.m[key] 13 | m.lock.RUnlock() 14 | return v, ok 15 | } 16 | 17 | func (m *RWLockMap) Set(key interface{}, value interface{}) { 18 | m.lock.Lock() 19 | m.m[key] = value 20 | m.lock.Unlock() 21 | } 22 | 23 | func (m *RWLockMap) Del(key interface{}) { 24 | m.lock.Lock() 25 | delete(m.m, key) 26 | m.lock.Unlock() 27 | } 28 | 29 | func CreateRWLockMap() *RWLockMap { 30 | m := make(map[interface{}]interface{}, 0) 31 | return &RWLockMap{m: m} 32 | } 33 | -------------------------------------------------------------------------------- /src/ch46/maps/sync_map_benchmark_adapter.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import "sync" 4 | 5 | func CreateSyncMapBenchmarkAdapter() *SyncMapBenchmarkAdapter { 6 | return &SyncMapBenchmarkAdapter{} 7 | } 8 | 9 | type SyncMapBenchmarkAdapter struct { 10 | m sync.Map 11 | } 12 | 13 | func (m *SyncMapBenchmarkAdapter) Set(key interface{}, val interface{}) { 14 | m.m.Store(key, val) 15 | } 16 | 17 | func (m *SyncMapBenchmarkAdapter) Get(key interface{}) (interface{}, bool) { 18 | return m.m.Load(key) 19 | } 20 | 21 | func (m *SyncMapBenchmarkAdapter) Del(key interface{}) { 22 | m.m.Delete(key) 23 | } 24 | -------------------------------------------------------------------------------- /src/ch47/gc_friendly/auto_growing/auto_growing_test.go: -------------------------------------------------------------------------------- 1 | package auto_growing 2 | 3 | import "testing" 4 | 5 | const numOfElems = 100000 6 | const times = 1000 7 | 8 | func TestAutoGrow(t *testing.T) { 9 | for i := 0; i < times; i++ { 10 | s := []int{} 11 | for j := 0; j < numOfElems; j++ { 12 | s = append(s, j) 13 | } 14 | } 15 | } 16 | 17 | func TestProperInit(t *testing.T) { 18 | for i := 0; i < times; i++ { 19 | s := make([]int, 0, numOfElems) 20 | for j := 0; j < numOfElems; j++ { 21 | s = append(s, j) 22 | } 23 | } 24 | } 25 | 26 | func TestOverSizeInit(t *testing.T) { 27 | for i := 0; i < times; i++ { 28 | s := make([]int, 0, numOfElems*8) 29 | for j := 0; j < numOfElems; j++ { 30 | s = append(s, j) 31 | } 32 | } 33 | } 34 | 35 | func BenchmarkAutoGrow(b *testing.B) { 36 | for i := 0; i < b.N; i++ { 37 | s := []int{} 38 | for j := 0; j < numOfElems; j++ { 39 | s = append(s, j) 40 | } 41 | } 42 | } 43 | 44 | func BenchmarkProperInit(b *testing.B) { 45 | for i := 0; i < b.N; i++ { 46 | s := make([]int, 0, numOfElems) 47 | for j := 0; j < numOfElems; j++ { 48 | s = append(s, j) 49 | } 50 | } 51 | } 52 | 53 | func BenchmarkOverSizeInit(b *testing.B) { 54 | for i := 0; i < b.N; i++ { 55 | s := make([]int, 0, numOfElems*8) 56 | for j := 0; j < numOfElems; j++ { 57 | s = append(s, j) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ch47/gc_friendly/pass_ref/pass_array_test.go: -------------------------------------------------------------------------------- 1 | package pass_ref 2 | 3 | import "testing" 4 | 5 | const NumOfElems = 1000 6 | 7 | type Content struct { 8 | Detail [10000]int 9 | } 10 | 11 | func withValue(arr [NumOfElems]Content) int { 12 | return 0 13 | } 14 | 15 | func withReference(arr *[NumOfElems]Content) int { 16 | return 0 17 | } 18 | 19 | func TestFn(t *testing.T) { 20 | var arr [NumOfElems]Content 21 | 22 | withValue(arr) 23 | withReference(&arr) 24 | } 25 | 26 | func BenchmarkPassingArrayWithValue(b *testing.B) { 27 | var arr [NumOfElems]Content 28 | b.ResetTimer() 29 | for i := 0; i < b.N; i++ { 30 | withValue(arr) 31 | } 32 | b.StopTimer() 33 | } 34 | 35 | func BenchmarkPassingArrayWithRef(b *testing.B) { 36 | var arr [NumOfElems]Content 37 | b.ResetTimer() 38 | for i := 0; i < b.N; i++ { 39 | withReference(&arr) 40 | } 41 | b.StopTimer() 42 | } 43 | -------------------------------------------------------------------------------- /src/ch47/gc_friendly/pass_ref/ref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch47/gc_friendly/pass_ref/ref.png -------------------------------------------------------------------------------- /src/ch47/gc_friendly/pass_ref/val.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenjianzhang/golearning/2579049b975bf2f8219891662030840038d5493f/src/ch47/gc_friendly/pass_ref/val.png -------------------------------------------------------------------------------- /src/ch48/concat_string_test.go: -------------------------------------------------------------------------------- 1 | package ch48 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strconv" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | const numbers = 100 12 | 13 | func BenchmarkSprintf(b *testing.B) { 14 | b.ResetTimer() 15 | for i := 0; i < b.N; i++ { 16 | var s string 17 | for j := 0; j < numbers; j++ { 18 | s = fmt.Sprintf("%v%v", s, j) 19 | } 20 | } 21 | b.StopTimer() 22 | } 23 | 24 | func BenchmarkStringBuilder(b *testing.B) { 25 | b.ResetTimer() 26 | for i := 0; i < b.N; i++ { 27 | var builder strings.Builder 28 | for j := 0; j < numbers; j++ { 29 | builder.WriteString(strconv.Itoa(j)) 30 | } 31 | _ = builder.String() 32 | } 33 | b.StopTimer() 34 | } 35 | 36 | func BenchmarkBytesBuf(b *testing.B) { 37 | b.ResetTimer() 38 | for i := 0; i < b.N; i++ { 39 | var buf bytes.Buffer 40 | for j := 0; j < numbers; j++ { 41 | buf.WriteString(strconv.Itoa(j)) 42 | } 43 | _ = buf.String() 44 | } 45 | b.StopTimer() 46 | } 47 | 48 | func BenchmarkStringAdd(b *testing.B) { 49 | b.ResetTimer() 50 | for i := 0; i < b.N; i++ { 51 | var s string 52 | for j := 0; j < numbers; j++ { 53 | s += strconv.Itoa(j) 54 | } 55 | } 56 | b.StopTimer() 57 | } 58 | 59 | type data struct { 60 | name string 61 | } 62 | 63 | func (p *data) print() { 64 | fmt.Println("name", p.name) 65 | } 66 | 67 | type printer interface { 68 | print() 69 | } 70 | 71 | func TestObjA(t *testing.T) { 72 | d1 := data{"one"} 73 | d1.print() 74 | 75 | var in printer = &data{"two"} 76 | in.print() 77 | t.Log(&data{"two"}) 78 | } 79 | -------------------------------------------------------------------------------- /src/ch5/loop/loop_test.go: -------------------------------------------------------------------------------- 1 | package loop 2 | 3 | import "testing" 4 | 5 | func TestWhileLoop(t *testing.T) { 6 | n := 0 7 | for n < 5 { 8 | t.Log(n) 9 | n++ 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ch6/array_test/array_test.go: -------------------------------------------------------------------------------- 1 | package array_test 2 | 3 | import "testing" 4 | 5 | func TestArrayInit(t *testing.T) { 6 | var arr [3]int 7 | arr1 := [4]int{1, 2, 3, 4} 8 | arr3 := [...]int{1, 3, 4, 5} 9 | arr1[1] = 5 10 | t.Log(arr[1], arr[2]) 11 | t.Log(arr1, arr3) 12 | } 13 | 14 | func TestArrayTravel(t *testing.T) { 15 | arr3 := [...]int{1, 3, 4, 5} 16 | for i := 0; i < len(arr3); i++ { 17 | t.Log(arr3[i]) 18 | } 19 | 20 | for idx, e := range arr3 { 21 | t.Log(idx, e) 22 | } 23 | } 24 | 25 | func TestArraySection(t *testing.T) { 26 | arr3 := [...]int{1, 2, 3, 4, 5} 27 | arr_sec := arr3[3:] 28 | t.Log(arr_sec) 29 | } 30 | -------------------------------------------------------------------------------- /src/ch6/slice_test/slice_test.go: -------------------------------------------------------------------------------- 1 | package slice_test 2 | 3 | import "testing" 4 | 5 | func TestSliceInit(t *testing.T) { 6 | var s0 []int 7 | t.Log(len(s0), cap(s0)) 8 | s0 = append(s0, 1) 9 | t.Log(len(s0), cap(s0)) 10 | 11 | s1 := []int{1, 2, 3, 4} 12 | t.Log(len(s1), cap(s1)) 13 | 14 | s2 := make([]int, 3, 5) 15 | t.Log(len(s2), cap(s2)) 16 | //t.Log(s2[0], s2[1], s2[3], s2[4]) 17 | //panic: runtime error: index out of range [recovered] 18 | //panic: runtime error: index out of range 19 | 20 | t.Log(s2[0], s2[1], s2[2]) 21 | 22 | s2 = append(s2, 1) 23 | t.Log(s2[0], s2[1], s2[2], s2[3]) 24 | t.Log(len(s2), cap(s2)) 25 | 26 | } 27 | 28 | func TestSliceGrowing(t *testing.T) { 29 | s := []int{} 30 | for i := 0; i < 10; i++ { 31 | s = append(s, i) 32 | t.Log(len(s), cap(s)) 33 | } 34 | } 35 | 36 | func TestSliceShareMemory(t *testing.T) { 37 | year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} 38 | Q2 := year[3:6] 39 | t.Log(Q2, len(Q2), cap(Q2)) 40 | 41 | summer := year[5:8] 42 | t.Log(summer, len(summer), cap(summer)) 43 | summer[0] = "Unknow" 44 | t.Log(Q2) 45 | t.Log(year) 46 | } 47 | 48 | func TestSliceCompare(t *testing.T) { 49 | a := []int{1, 2, 3, 4} 50 | b := []int{1, 2, 3, 4} 51 | if a == b { 52 | t.Log("equal") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ch7/map/map_test.go: -------------------------------------------------------------------------------- 1 | package map_test 2 | 3 | import "testing" 4 | 5 | func TestInitMap(t *testing.T) { 6 | m1 := map[int]int{1: 1, 2: 4, 3: 9} 7 | t.Log(m1[2]) 8 | t.Logf("len m1=%d", len(m1)) 9 | m2 := map[int]int{} 10 | 11 | m2[4] = 16 12 | t.Logf("len m2=%d", len(m2)) 13 | 14 | m3 := make(map[int]int, 10) 15 | t.Logf("len m3=%d", len(m3)) 16 | } 17 | 18 | func TestAccessNotExistingKey(t *testing.T) { 19 | m1 := map[int]int{} 20 | t.Log(m1[1]) 21 | m1[2] = 0 22 | t.Log(m1[2]) 23 | m1[3] = 0 24 | if v, ok := m1[3]; ok { 25 | t.Logf("key 3's value is %d", v) 26 | } else { 27 | t.Log("key 3 is not existing.") 28 | } 29 | } 30 | 31 | func TestTracelMap(t *testing.T) { 32 | m1 := map[int]int{1: 1, 2: 4, 3: 9} 33 | for k, v := range m1 { 34 | t.Log(k, v) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ch8/map/map_test.go: -------------------------------------------------------------------------------- 1 | package map_ext 2 | 3 | import "testing" 4 | 5 | func TestMap(t *testing.T) { 6 | m := map[int]func(op int) int{} 7 | m[1] = func(op int) int { return op } 8 | m[2] = func(op int) int { return op * op } 9 | m[3] = func(op int) int { return op * op * op } 10 | t.Log(m[1](2), m[2](2), m[3](2)) 11 | } 12 | 13 | func TestMapForSet(t *testing.T) { 14 | mySet := map[int]bool{} 15 | mySet[1] = true 16 | n := 3 17 | if mySet[n] { 18 | t.Logf("%d is existing", n) 19 | } else { 20 | t.Logf("%d is not existing", n) 21 | } 22 | mySet[3] = true 23 | t.Log(len(mySet)) 24 | delete(mySet, 1) 25 | n = 1 26 | if mySet[n] { 27 | t.Logf("%d is existing", n) 28 | } else { 29 | t.Logf("%d is not existing", n) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ch9/string/string_fun_test.go: -------------------------------------------------------------------------------- 1 | package string_fun_test 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestStringFn(t *testing.T) { 10 | s := "A,B,C" 11 | parts := strings.Split(s, ",") 12 | for _, part := range parts { 13 | t.Log(part) 14 | } 15 | t.Log(strings.Join(parts, "-")) 16 | } 17 | 18 | func TestConv(t *testing.T) { 19 | s := strconv.Itoa(10) 20 | t.Log("str:" + s) 21 | if i, err := strconv.Atoi("10"); err == nil { 22 | t.Log(10 + i) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/ch9/string/string_test.go: -------------------------------------------------------------------------------- 1 | package string_fun_test 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestString(t *testing.T) { 8 | var s string 9 | t.Log(s) //初始化为默认零值"" 10 | s = "hello" 11 | t.Log(len(s)) 12 | //s[1] = '3' //string是不可变的byte slice 13 | s = "\xE4\xB8\xA5" 14 | t.Log(s) 15 | t.Log(len(s)) 16 | s = "中" 17 | t.Log(len(s)) 18 | c := []rune(s) 19 | t.Log(len(c)) 20 | //t.Log("rune size:", unsafe.Sizeof(c[0])) 21 | t.Logf("中 unicode %x", c[0]) 22 | t.Logf("中 utf8 %x", s) 23 | } 24 | 25 | func TestStringToRune(t *testing.T) { 26 | s := "中华人民共和国" 27 | for _, c := range s { 28 | t.Logf("%[1]c %[1]d", c) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/eventcenter/eventcenter_test.go: -------------------------------------------------------------------------------- 1 | package eventcenter 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type ( 9 | Event struct { 10 | Msg string 11 | } 12 | 13 | Observcer interface { 14 | OnNotify(Event) 15 | } 16 | 17 | Notifier interface { 18 | Register(Observcer) 19 | 20 | UNRegister(Observcer) 21 | 22 | Notifier(Event) 23 | } 24 | 25 | EventCenter struct { 26 | observcers []Observcer 27 | } 28 | 29 | EventReceiver struct { 30 | } 31 | ) 32 | 33 | func (e *EventCenter) Register(observcer Observcer) { 34 | e.observcers = append(e.observcers, observcer) 35 | } 36 | 37 | func (e *EventCenter) UNRegister(observcer Observcer) { 38 | for i, o := range e.observcers { 39 | if o == observcer { 40 | e.observcers = append(e.observcers[:i], e.observcers[i+1:]...) 41 | break 42 | } 43 | } 44 | } 45 | 46 | func (e *EventCenter) Notify(event Event) { 47 | for _, o := range e.observcers { 48 | o.OnNotify(event) 49 | } 50 | } 51 | 52 | func (e EventReceiver) OnNotify(event Event) { 53 | fmt.Printf("Receiver receive: %s\n", event.Msg) 54 | } 55 | 56 | func NewEventCenter() *EventCenter { 57 | ec := EventCenter{} 58 | ec.observcers = make([]Observcer, 0) 59 | return &ec 60 | } 61 | 62 | func TestEventCenter(T *testing.T) { 63 | eventCenter := NewEventCenter() 64 | recover1 := EventReceiver{} 65 | recover2 := EventReceiver{} 66 | 67 | eventCenter.Register(recover1) 68 | eventCenter.Register(recover2) 69 | 70 | eventCenter.Notify(Event{Msg: "hello go !"}) 71 | 72 | eventCenter.UNRegister(recover1) 73 | 74 | eventCenter.Notify(Event{"hello docker"}) 75 | } 76 | -------------------------------------------------------------------------------- /src/mianshi/mianshi_test.go: -------------------------------------------------------------------------------- 1 | package mianshi 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "sync" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | func Add(a int, b int) int { 12 | c := a + b 13 | fmt.Println(a, b, c) 14 | return c 15 | } 16 | 17 | func TestAdd(t *testing.T) { 18 | a := 2 19 | b := 4 20 | defer Add(a, b) 21 | a = 3 22 | defer Add(a, b) 23 | b = 5 24 | } 25 | 26 | type Slice []int 27 | 28 | func NewSlice() Slice { 29 | return make(Slice, 0) 30 | } 31 | func (s *Slice) Add(elem int) *Slice { 32 | *s = append(*s, elem) 33 | fmt.Print(elem) 34 | return s 35 | } 36 | func TestAA(t *testing.T) { 37 | s := NewSlice() 38 | defer func() { 39 | s.Add(1).Add(2) 40 | }() 41 | s.Add(3) 42 | } 43 | 44 | type Orange struct { 45 | Quantity int 46 | } 47 | 48 | func (o *Orange) Increase(n int) { 49 | o.Quantity += n 50 | } 51 | 52 | func (o *Orange) Decrease(n int) { 53 | o.Quantity -= n 54 | } 55 | 56 | func (o *Orange) String() string { 57 | return fmt.Sprintf("%#v", o.Quantity) 58 | } 59 | 60 | func TestAA1(t *testing.T) { 61 | //var orange Orange 62 | //orange.Increase(10) 63 | //orange.Decrease(5) 64 | //fmt.Println(orange) 65 | 66 | //slice := []int{0, 1, 2, 3} 67 | //m := make(map[int]*int) 68 | // 69 | //for key, val := range slice { 70 | // m[key] = &val 71 | // fmt.Println(key, "--->", val) 72 | //} 73 | // 74 | //for k, v := range m { 75 | // fmt.Println("v:", v) 76 | // fmt.Println(k, "->", *v) 77 | //} 78 | 79 | //s := make([]int, 0) 80 | // //s = append(s, 1, 2, 3) 81 | // //fmt.Println(s) 82 | 83 | //list := make([]int, 0) 84 | //list = append(list, 1) 85 | //fmt.Println(list) 86 | 87 | //s1 := []int{1, 2, 3} 88 | //s2 := []int{4, 5} 89 | //s1 = append(s1, s2) 90 | //fmt.Println(s1) 91 | 92 | var ( 93 | size = 1024 94 | max_size = size * 2 95 | ) 96 | fmt.Println(size, max_size) 97 | 98 | sn1 := struct { 99 | age int 100 | name string 101 | }{age: 11, name: "qq"} 102 | sn2 := struct { 103 | age int 104 | name string 105 | }{age: 11, name: "qq"} 106 | 107 | if sn1 == sn2 { 108 | fmt.Println("sn1 == sn2") 109 | } 110 | 111 | //sm1 := struct { 112 | // age int 113 | // m map[string]string 114 | //}{age: 11, m: map[string]string{"a": "1"}} 115 | //sm2 := struct { 116 | // age int 117 | // m map[string]string 118 | //}{age: 11, m: map[string]string{"a": "1"}} 119 | 120 | //if sm1.m == sm2.m { 121 | // fmt.Println("sm1 == sm2") 122 | //} 123 | } 124 | 125 | func TestPrintLog(t *testing.T) { 126 | var ch = make(chan string, 100) 127 | var wg sync.WaitGroup 128 | wg.Add(2) 129 | go send(ch, &wg) 130 | go receive(ch, &wg) 131 | 132 | wg.Wait() 133 | fmt.Println("over") 134 | 135 | defer close(ch) 136 | } 137 | 138 | func send(ch chan string, wg *sync.WaitGroup) { 139 | for i := 0; i < 10000; i++ { 140 | ch <- "消息:" + strconv.Itoa(i) 141 | } 142 | wg.Done() 143 | } 144 | 145 | func receive(ch chan string, wg *sync.WaitGroup) { 146 | var loglist [100]string 147 | y := 0 148 | for { 149 | if y >= 10000 { 150 | fmt.Println("y >= 10000", y) 151 | wg.Done() 152 | return 153 | } 154 | for i := 0; i < 100; i++ { 155 | select { 156 | case loglist[i] = <-ch: 157 | y++ 158 | case <-time.After(time.Second * 1): 159 | return 160 | } 161 | } 162 | fmt.Println(loglist) 163 | } 164 | } 165 | --------------------------------------------------------------------------------