├── code ├── ch34 │ └── unit_test │ │ ├── functions.go │ │ └── functions_test.go ├── ch48 │ ├── lock │ │ ├── lock.test │ │ └── lock_test.go │ └── maps │ │ ├── sync_map_benchmark_adapter.go │ │ ├── rw_map.go │ │ ├── concurrent_map_benchmark_adapter.go │ │ └── map_benchmark_test.go ├── ch5 │ ├── loop │ │ └── loop_test.go │ └── condition │ │ └── condition_test.go ├── ch1 │ └── hello │ │ └── hello_world.go ├── ch15 │ ├── client │ │ └── package_test.go │ ├── remote_package │ │ └── remote_package_test.go │ └── series │ │ └── my_series.go ├── ch47 │ ├── structs.go │ ├── optimization_test.go │ ├── optmization.go │ └── structs_easyjson.go ├── ch42 │ └── json │ │ ├── struct_def.go │ │ └── embedded_json_test.go ├── ch43 │ └── easyjson │ │ ├── struct_def.go │ │ ├── embedded_json_test.go │ │ └── struct_def_easyjson.go ├── ch16 │ └── groutine │ │ └── groutine_test.go ├── ch14 │ ├── panic_recover │ │ └── panic_recover_test.go │ └── error │ │ └── err_test.go ├── ch11 │ ├── interface │ │ └── interface_test.go │ ├── customer_type │ │ └── customer_type_test.go │ └── encapsulation │ │ └── encap_test.go ├── ch2 │ ├── constant_test │ │ └── constant_try_test.go │ └── fib │ │ └── fib_test.go ├── ch40 │ └── pipe_filter │ │ └── pipe_filter │ │ ├── straigt_pipeline_test.go │ │ ├── filter.go │ │ ├── sum_filter.go │ │ ├── sum_filter_test.go │ │ ├── split_filter.go │ │ ├── to_int_filter.go │ │ ├── split_filter_test.go │ │ ├── to_int_filter_test.go │ │ └── straigt_pipeline.go ├── ch9 │ └── string │ │ ├── string_fun_test.go │ │ └── string_test.go ├── ch44 │ └── hello_http │ │ └── hello_http.go ├── ch12 │ └── extension │ │ └── extension_test.go ├── ch36 │ └── bdd │ │ └── bdd_spec_test.go ├── ch3 │ └── type_test │ │ └── type_test.go ├── ch32 │ └── obj_pool │ │ ├── obj_pool_test.go │ │ └── obj_pool.go ├── ch4 │ └── operator_test │ │ └── operator_test.go ├── ch45 │ ├── http_router │ │ └── http_router.go │ └── roa │ │ └── resource_oriented_arc.go ├── ch6 │ ├── array_test │ │ └── array_test.go │ └── slice_test │ │ └── slice_test.go ├── ch13 │ ├── empty_interface │ │ └── empty_interface_test.go │ └── polymorphsim │ │ └── polymorphsim_test.go ├── ch19 │ └── select │ │ └── select_test.go ├── ch23 │ └── singleton │ │ └── once_test.go ├── ch22 │ └── cancel_by_context │ │ └── cancel_by_context_test.go ├── ch24 │ └── util_anyone_reply │ │ └── first_response_test.go ├── ch8 │ └── map │ │ └── map_ext_test.go ├── ch7 │ └── map │ │ └── map_test.go ├── ch46 │ └── tools │ │ ├── http │ │ └── fb_server.go │ │ └── file │ │ └── prof.go ├── ch20 │ └── channel_close │ │ └── channel_close_test.go ├── ch21 │ └── cancel_by_close │ │ └── cancel_test.go ├── ch18 │ └── csp │ │ └── async_service_test.go ├── ch33 │ └── obj_cache │ │ └── sync_pool_test.go ├── ch49 │ └── gc_friendly │ │ ├── passing_ref │ │ └── pass_array_test.go │ │ └── auto_growing │ │ └── auto_growing_test.go ├── ch17 │ └── share_mem │ │ └── share_mem_test.go ├── ch25 │ └── until_all_done │ │ └── until_all_done_test.go ├── ch10 │ └── func │ │ └── func_test.go ├── ch50 │ └── concat_string_test.go ├── ch35 │ └── benchmark │ │ └── concat_string_test.go ├── ch39 │ └── unsafe_programming │ │ └── unsafe_test.go ├── ch41 │ └── microkernel │ │ ├── agent_test.go │ │ └── agent.go ├── ch37 │ └── reflect │ │ └── reflect_test.go └── ch38 │ └── flexible_reflect_test.go └── doc └── 极客时间-Go语言从入门到实战-课件.pdf /code/ch34/unit_test/functions.go: -------------------------------------------------------------------------------- 1 | package testing 2 | 3 | func square(op int) int { 4 | return op * op 5 | } 6 | -------------------------------------------------------------------------------- /code/ch48/lock/lock.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superman-geek-time/go_learning/HEAD/code/ch48/lock/lock.test -------------------------------------------------------------------------------- /doc/极客时间-Go语言从入门到实战-课件.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superman-geek-time/go_learning/HEAD/doc/极客时间-Go语言从入门到实战-课件.pdf -------------------------------------------------------------------------------- /code/ch5/loop/loop_test.go: -------------------------------------------------------------------------------- 1 | package loop_test 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 | -------------------------------------------------------------------------------- /code/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 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/ch15/client/package_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "ch15/series" 5 | "testing" 6 | ) 7 | 8 | func TestPackage(t *testing.T) { 9 | t.Log(series.GetFibonacciSerie(5)) 10 | t.Log(series.Square(5)) 11 | } 12 | -------------------------------------------------------------------------------- /code/ch47/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 | -------------------------------------------------------------------------------- /code/ch15/remote_package/remote_package_test.go: -------------------------------------------------------------------------------- 1 | package remote 2 | 3 | import ( 4 | "testing" 5 | 6 | cm "github.com/easierway/concurrent_map" 7 | ) 8 | 9 | func TestConcurrentMap(t *testing.T) { 10 | m := cm.CreateConcurrentMap(99) 11 | m.Set(cm.StrKey("key"), 10) 12 | t.Log(m.Get(cm.StrKey("key"))) 13 | } 14 | -------------------------------------------------------------------------------- /code/ch42/json/struct_def.go: -------------------------------------------------------------------------------- 1 | package jsontest 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 | -------------------------------------------------------------------------------- /code/ch43/easyjson/struct_def.go: -------------------------------------------------------------------------------- 1 | package jsontest 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 | -------------------------------------------------------------------------------- /code/ch16/groutine/groutine_test.go: -------------------------------------------------------------------------------- 1 | package groutine_test 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 | //time.Sleep(time.Second * 1) 13 | fmt.Println(i) 14 | }(i) 15 | } 16 | time.Sleep(time.Millisecond * 50) 17 | } 18 | -------------------------------------------------------------------------------- /code/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 GetFibonacciSerie(n int) []int { 18 | ret := []int{1, 1} 19 | for i := 2; i < n; i++ { 20 | ret = append(ret, ret[i-2]+ret[i-1]) 21 | } 22 | return ret 23 | } 24 | -------------------------------------------------------------------------------- /code/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 | 11 | defer func() { 12 | if err := recover(); err != nil { 13 | fmt.Println("recovered from ", err) 14 | } 15 | }() 16 | fmt.Println("Start") 17 | panic(errors.New("Something wrong!")) 18 | //os.Exit(-1) 19 | //fmt.Println("End") 20 | } 21 | -------------------------------------------------------------------------------- /code/ch11/interface/interface_test.go: -------------------------------------------------------------------------------- 1 | package interface_test 2 | 3 | import "testing" 4 | 5 | type Programmer interface { 6 | WriteHelloWorld() string 7 | } 8 | 9 | type GoProgrammer struct { 10 | } 11 | 12 | func (g *GoProgrammer) WriteHelloWorld() string { 13 | return "fmt.Println(\"Hello World\")" 14 | } 15 | 16 | func TestClient(t *testing.T) { 17 | var p Programmer 18 | p = new(GoProgrammer) 19 | t.Log(p.WriteHelloWorld()) 20 | } 21 | -------------------------------------------------------------------------------- /code/ch2/constant_test/constant_try_test.go: -------------------------------------------------------------------------------- 1 | package constant_test 2 | 3 | import "testing" 4 | 5 | const ( 6 | Monday = 1 + iota 7 | Tuesday 8 | Wednesday 9 | ) 10 | 11 | const ( 12 | Readable = 1 << iota 13 | Writable 14 | Executable 15 | ) 16 | 17 | func TestConstantTry(t *testing.T) { 18 | t.Log(Monday, Tuesday) 19 | } 20 | 21 | func TestConstantTry1(t *testing.T) { 22 | a := 1 //0001 23 | t.Log(a&Readable == Readable, a&Writable == Writable, a&Executable == Executable) 24 | } 25 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/straigt_pipeline_test.go: -------------------------------------------------------------------------------- 1 | package pipefilter 2 | 3 | import "testing" 4 | 5 | func TestStraightPipeline(t *testing.T) { 6 | spliter := NewSplitFilter(",") 7 | converter := NewToIntFilter() 8 | sum := NewSumFilter() 9 | sp := NewStraightPipeline("p1", spliter, converter, sum) 10 | ret, err := sp.Process("1,2,3") 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | if ret != 6 { 15 | t.Fatalf("The expected is 6, but the actual is %d", ret) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/ch9/string/string_fun_test.go: -------------------------------------------------------------------------------- 1 | package string_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 | -------------------------------------------------------------------------------- /code/ch44/hello_http/hello_http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "time" 8 | ) 9 | 10 | func main() { 11 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 12 | fmt.Fprintf(w, "Hello World!") 13 | }) 14 | http.HandleFunc("/time/", func(w http.ResponseWriter, r *http.Request) { 15 | t := time.Now() 16 | timeStr := fmt.Sprintf("{\"time\": \"%s\"}", t) 17 | w.Write([]byte(timeStr)) 18 | }) 19 | 20 | http.ListenAndServe(":8080", nil) 21 | } 22 | -------------------------------------------------------------------------------- /code/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 | Pet 22 | } 23 | 24 | func (d *Dog) Speak() { 25 | fmt.Print("Wang!") 26 | } 27 | 28 | func TestDog(t *testing.T) { 29 | dog := new(Dog) 30 | 31 | dog.SpeakTo("Chao") 32 | } 33 | -------------------------------------------------------------------------------- /code/ch36/bdd/bdd_spec_test.go: -------------------------------------------------------------------------------- 1 | package testing 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/smartystreets/goconvey/convey" 7 | ) 8 | 9 | func TestSpec(t *testing.T) { 10 | 11 | // Only pass t into top-level Convey calls 12 | Convey("Given 2 even numbers", t, func() { 13 | a := 3 14 | b := 4 15 | 16 | Convey("When add the two numbers", func() { 17 | c := a + b 18 | 19 | Convey("Then the result is still even", func() { 20 | So(c%2, ShouldEqual, 0) 21 | }) 22 | }) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/filter.go: -------------------------------------------------------------------------------- 1 | // Package pipefilter is to define the interfaces and the structures for pipe-filter style implementation 2 | package pipefilter 3 | 4 | // Request is the input of the filter 5 | type Request interface{} 6 | 7 | // Response is the output of the filter 8 | type Response interface{} 9 | 10 | // Filter interface is the definition of the data processing components 11 | // Pipe-Filter structure 12 | type Filter interface { 13 | Process(data Request) (Response, error) 14 | } 15 | -------------------------------------------------------------------------------- /code/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 int32 = 1 9 | var b int64 10 | b = int64(a) 11 | var c MyInt 12 | c = MyInt(b) 13 | t.Log(a, b, c) 14 | } 15 | 16 | func TestPoint(t *testing.T) { 17 | a := 1 18 | aPtr := &a 19 | //aPtr = aPtr + 1 20 | t.Log(a, aPtr) 21 | t.Logf("%T %T", a, aPtr) 22 | } 23 | 24 | func TestString(t *testing.T) { 25 | var s string 26 | t.Log("*" + s + "*") //初始化零值是“” 27 | t.Log(len(s)) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /code/ch2/fib/fib_test.go: -------------------------------------------------------------------------------- 1 | package fib 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestFibList(t *testing.T) { 8 | // var a int = 1 9 | // var b int = 1 10 | // var ( 11 | // a int = 1 12 | // b = 1 13 | // ) 14 | a := 1 15 | // a := 1 16 | b := 1 17 | t.Log(a) 18 | for i := 0; i < 5; i++ { 19 | t.Log(" ", b) 20 | tmp := a 21 | a = b 22 | b = tmp + a 23 | } 24 | 25 | } 26 | 27 | func TestExchange(t *testing.T) { 28 | a := 1 29 | b := 2 30 | // tmp := a 31 | // a = b 32 | // b = tmp 33 | a, b = b, a 34 | t.Log(a, b) 35 | } 36 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/sum_filter.go: -------------------------------------------------------------------------------- 1 | package pipefilter 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 | -------------------------------------------------------------------------------- /code/ch5/condition/condition_test.go: -------------------------------------------------------------------------------- 1 | package condition_test 2 | 3 | import "testing" 4 | 5 | func TestSwitchMultiCase(t *testing.T) { 6 | for i := 0; i < 5; i++ { 7 | switch i { 8 | case 0, 2: 9 | t.Log("Even") 10 | case 1, 3: 11 | t.Log("Odd") 12 | default: 13 | t.Log("it is not 0-3") 14 | } 15 | } 16 | } 17 | 18 | func TestSwitchCaseCondition(t *testing.T) { 19 | for i := 0; i < 5; i++ { 20 | switch { 21 | case i%2 == 0: 22 | t.Log("Even") 23 | case i%2 == 1: 24 | t.Log("Odd") 25 | default: 26 | t.Log("unknow") 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/ch11/customer_type/customer_type_test.go: -------------------------------------------------------------------------------- 1 | package customer_type 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | type IntConv func(op int) int 10 | 11 | func timeSpent(inner IntConv) 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 | -------------------------------------------------------------------------------- /code/ch32/obj_pool/obj_pool_test.go: -------------------------------------------------------------------------------- 1 | package object_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 | 26 | fmt.Println("Done") 27 | } 28 | -------------------------------------------------------------------------------- /code/ch48/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 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/sum_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipefilter 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 | -------------------------------------------------------------------------------- /code/ch42/json/embedded_json_test.go: -------------------------------------------------------------------------------- 1 | package jsontest 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 | -------------------------------------------------------------------------------- /code/ch4/operator_test/operator_test.go: -------------------------------------------------------------------------------- 1 | package operator_test 2 | 3 | import "testing" 4 | 5 | const ( 6 | Readable = 1 << iota 7 | Writable 8 | Executable 9 | ) 10 | 11 | func TestCompareArray(t *testing.T) { 12 | a := [...]int{1, 2, 3, 4} 13 | b := [...]int{1, 3, 2, 4} 14 | // c := [...]int{1, 2, 3, 4, 5} 15 | d := [...]int{1, 2, 3, 4} 16 | t.Log(a == b) 17 | //t.Log(a == c) 18 | t.Log(a == d) 19 | } 20 | 21 | func TestBitClear(t *testing.T) { 22 | a := 7 //0111 23 | a = a &^ Readable 24 | a = a &^ Executable 25 | t.Log(a&Readable == Readable, a&Writable == Writable, a&Executable == Executable) 26 | } 27 | -------------------------------------------------------------------------------- /code/ch45/http_router/http_router.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | 8 | "github.com/julienschmidt/httprouter" 9 | ) 10 | 11 | func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 12 | fmt.Fprint(w, "Welcome!\n") 13 | } 14 | 15 | func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { 16 | fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) 17 | } 18 | 19 | func main() { 20 | router := httprouter.New() 21 | router.GET("/", Index) 22 | router.GET("/hello/:name", Hello) 23 | 24 | log.Fatal(http.ListenAndServe(":8080", router)) 25 | } 26 | -------------------------------------------------------------------------------- /code/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 | for _, e := range arr3 { 20 | t.Log(e) 21 | } 22 | } 23 | 24 | func TestArraySection(t *testing.T) { 25 | arr3 := [...]int{1, 2, 3, 4, 5} 26 | arr3_sec := arr3[:] 27 | t.Log(arr3_sec) 28 | } 29 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/split_filter.go: -------------------------------------------------------------------------------- 1 | package pipefilter 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | var SplitFilterWrongFormatError = errors.New("input 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 | -------------------------------------------------------------------------------- /code/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("stirng", s) 15 | // return 16 | // } 17 | // fmt.Println("Unknow Type") 18 | switch v := p.(type) { 19 | case int: 20 | fmt.Println("Integer", v) 21 | case string: 22 | fmt.Println("String", v) 23 | default: 24 | fmt.Println("Unknow Type") 25 | } 26 | } 27 | 28 | func TestEmptyInterfaceAssertion(t *testing.T) { 29 | DoSomething(10) 30 | DoSomething("10") 31 | } 32 | -------------------------------------------------------------------------------- /code/ch19/select/select_test.go: -------------------------------------------------------------------------------- 1 | package select_test 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, 1) 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 | -------------------------------------------------------------------------------- /code/ch9/string/string_test.go: -------------------------------------------------------------------------------- 1 | package string_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 | s = "\xE4\xBA\xBB\xFF" 15 | t.Log(s) 16 | t.Log(len(s)) 17 | s = "中" 18 | t.Log(len(s)) //是byte数 19 | 20 | c := []rune(s) 21 | t.Log(len(c)) 22 | // t.Log("rune size:", unsafe.Sizeof(c[0])) 23 | t.Logf("中 unicode %x", c[0]) 24 | t.Logf("中 UTF8 %x", s) 25 | } 26 | 27 | func TestStringToRune(t *testing.T) { 28 | s := "中华人民共和国" 29 | for _, c := range s { 30 | t.Logf("%[1]c %[1]x", c) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/ch23/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 | data string 12 | } 13 | 14 | var singleInstance *Singleton 15 | var once sync.Once 16 | 17 | func GetSingletonObj() *Singleton { 18 | once.Do(func() { 19 | fmt.Println("Create Obj") 20 | singleInstance = new(Singleton) 21 | }) 22 | return singleInstance 23 | } 24 | 25 | func TestGetSingletonObj(t *testing.T) { 26 | var wg sync.WaitGroup 27 | for i := 0; i < 10; i++ { 28 | wg.Add(1) 29 | go func() { 30 | obj := GetSingletonObj() 31 | fmt.Printf("%X\n", unsafe.Pointer(obj)) 32 | wg.Done() 33 | }() 34 | } 35 | wg.Wait() 36 | } 37 | -------------------------------------------------------------------------------- /code/ch22/cancel_by_context/cancel_by_context_test.go: -------------------------------------------------------------------------------- 1 | package cancel 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 | }(i, ctx) 31 | } 32 | cancel() 33 | time.Sleep(time.Second * 1) 34 | } 35 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/to_int_filter.go: -------------------------------------------------------------------------------- 1 | package pipefilter 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 | -------------------------------------------------------------------------------- /code/ch48/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 | -------------------------------------------------------------------------------- /code/ch24/util_anyone_reply/first_response_test.go: -------------------------------------------------------------------------------- 1 | package concurrency 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", id) 13 | } 14 | 15 | func FirstResponse() 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 TestFirstResponse(t *testing.T) { 28 | t.Log("Before:", runtime.NumGoroutine()) 29 | t.Log(FirstResponse()) 30 | time.Sleep(time.Second * 1) 31 | t.Log("After:", runtime.NumGoroutine()) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/split_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipefilter 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 | -------------------------------------------------------------------------------- /code/ch8/map/map_ext_test.go: -------------------------------------------------------------------------------- 1 | package map_ext 2 | 3 | import "testing" 4 | 5 | func TestMapWithFunValue(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 | -------------------------------------------------------------------------------- /code/ch7/map/map_test.go: -------------------------------------------------------------------------------- 1 | package my_map 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 | m2[4] = 16 11 | t.Logf("len m2=%d", len(m2)) 12 | m3 := make(map[int]int, 10) 13 | t.Logf("len m3=%d", len(m3)) 14 | } 15 | 16 | func TestAccessNotExistingKey(t *testing.T) { 17 | m1 := map[int]int{} 18 | t.Log(m1[1]) 19 | m1[2] = 0 20 | t.Log(m1[2]) 21 | m1[3] = 0 22 | if v, ok := m1[3]; ok { 23 | t.Logf("Key 3's value is %d", v) 24 | } else { 25 | t.Log("key 3 is not existing.") 26 | } 27 | } 28 | 29 | func TestTravelMap(t *testing.T) { 30 | m1 := map[int]int{1: 1, 2: 4, 3: 9} 31 | for k, v := range m1 { 32 | t.Log(k, v) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/ch13/polymorphsim/polymorphsim_test.go: -------------------------------------------------------------------------------- 1 | package polymorphism 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | type Code string 9 | type Programmer interface { 10 | WriteHelloWorld() Code 11 | } 12 | 13 | type GoProgrammer struct { 14 | } 15 | 16 | func (p *GoProgrammer) WriteHelloWorld() Code { 17 | return "fmt.Println(\"Hello World!\")" 18 | } 19 | 20 | type JavaProgrammer struct { 21 | } 22 | 23 | func (p *JavaProgrammer) WriteHelloWorld() Code { 24 | return "System.out.Println(\"Hello World!\")" 25 | } 26 | 27 | func writeFirstProgram(p Programmer) { 28 | fmt.Printf("%T %v\n", p, p.WriteHelloWorld()) 29 | } 30 | 31 | func TestPolymorphism(t *testing.T) { 32 | goProg := &GoProgrammer{} 33 | javaProg := new(JavaProgrammer) 34 | writeFirstProgram(goProg) 35 | writeFirstProgram(javaProg) 36 | } 37 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/to_int_filter_test.go: -------------------------------------------------------------------------------- 1 | package pipefilter 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 | -------------------------------------------------------------------------------- /code/ch46/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 | -------------------------------------------------------------------------------- /code/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 | 16 | wg.Done() 17 | }() 18 | 19 | } 20 | 21 | func dataReceiver(ch chan int, wg *sync.WaitGroup) { 22 | go func() { 23 | for { 24 | if data, ok := <-ch; ok { 25 | fmt.Println(data) 26 | } else { 27 | break 28 | } 29 | } 30 | wg.Done() 31 | }() 32 | 33 | } 34 | 35 | func TestCloseChannel(t *testing.T) { 36 | var wg sync.WaitGroup 37 | ch := make(chan int) 38 | wg.Add(1) 39 | dataProducer(ch, &wg) 40 | wg.Add(1) 41 | dataReceiver(ch, &wg) 42 | // wg.Add(1) 43 | // dataReceiver(ch, &wg) 44 | wg.Wait() 45 | 46 | } 47 | -------------------------------------------------------------------------------- /code/ch47/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 BenchmarkProcessRequest(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 | -------------------------------------------------------------------------------- /code/ch40/pipe_filter/pipe_filter/straigt_pipeline.go: -------------------------------------------------------------------------------- 1 | package pipefilter 2 | 3 | // NewStraightPipeline create a new StraightPipelineWithWallTime 4 | func NewStraightPipeline(name string, filters ...Filter) *StraightPipeline { 5 | return &StraightPipeline{ 6 | Name: name, 7 | Filters: &filters, 8 | } 9 | } 10 | 11 | // StraightPipeline is composed of the filters, and the filters are piled as a straigt line. 12 | type StraightPipeline struct { 13 | Name string 14 | Filters *[]Filter 15 | } 16 | 17 | // Process is to process the coming data by the pipeline 18 | func (f *StraightPipeline) Process(data Request) (Response, error) { 19 | var ret interface{} 20 | var err error 21 | for _, filter := range *f.Filters { 22 | ret, err = filter.Process(data) 23 | if err != nil { 24 | return ret, err 25 | } 26 | data = ret 27 | } 28 | return ret, err 29 | } 30 | -------------------------------------------------------------------------------- /code/ch21/cancel_by_close/cancel_test.go: -------------------------------------------------------------------------------- 1 | package concurrency 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 | 26 | func TestCancel(t *testing.T) { 27 | cancelChan := make(chan struct{}, 0) 28 | for i := 0; i < 5; i++ { 29 | go func(i int, cancelCh chan struct{}) { 30 | for { 31 | if isCancelled(cancelCh) { 32 | break 33 | } 34 | time.Sleep(time.Millisecond * 5) 35 | } 36 | fmt.Println(i, "Cancelled") 37 | }(i, cancelChan) 38 | } 39 | cancel_2(cancelChan) 40 | time.Sleep(time.Second * 1) 41 | } 42 | -------------------------------------------------------------------------------- /code/ch48/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 | -------------------------------------------------------------------------------- /code/ch32/obj_pool/obj_pool.go: -------------------------------------------------------------------------------- 1 | package object_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("time out") 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 | -------------------------------------------------------------------------------- /code/ch18/csp/async_service_test.go: -------------------------------------------------------------------------------- 1 | package concurrency 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, 1) 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 | // 38 | func TestAsynService(t *testing.T) { 39 | retCh := AsyncService() 40 | otherTask() 41 | fmt.Println(<-retCh) 42 | time.Sleep(time.Second * 1) 43 | } 44 | -------------------------------------------------------------------------------- /code/ch33/obj_cache/sync_pool_test.go: -------------------------------------------------------------------------------- 1 | package object_pool 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 | 18 | v := pool.Get().(int) 19 | fmt.Println(v) 20 | pool.Put(3) 21 | runtime.GC() //GC 会清除sync.pool中缓存的对象 22 | v1, _ := pool.Get().(int) 23 | fmt.Println(v1) 24 | } 25 | 26 | func TestSyncPoolInMultiGroutine(t *testing.T) { 27 | pool := &sync.Pool{ 28 | New: func() interface{} { 29 | fmt.Println("Create a new object.") 30 | return 10 31 | }, 32 | } 33 | 34 | pool.Put(100) 35 | pool.Put(100) 36 | pool.Put(100) 37 | 38 | var wg sync.WaitGroup 39 | for i := 0; i < 10; i++ { 40 | wg.Add(1) 41 | go func(id int) { 42 | fmt.Println(pool.Get()) 43 | wg.Done() 44 | }(i) 45 | } 46 | wg.Wait() 47 | } 48 | -------------------------------------------------------------------------------- /code/ch34/unit_test/functions_test.go: -------------------------------------------------------------------------------- 1 | package testing 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestSquare(t *testing.T) { 11 | inputs := [...]int{1, 2, 3} 12 | expected := [...]int{1, 4, 9} 13 | for i := 0; i < len(inputs); i++ { 14 | ret := square(inputs[i]) 15 | if ret != expected[i] { 16 | t.Errorf("input is %d, the expected is %d, the actual %d", 17 | inputs[i], expected[i], ret) 18 | } 19 | } 20 | } 21 | 22 | func TestErrorInCode(t *testing.T) { 23 | fmt.Println("Start") 24 | t.Error("Error") 25 | fmt.Println("End") 26 | } 27 | 28 | func TestFailInCode(t *testing.T) { 29 | fmt.Println("Start") 30 | t.Fatal("Error") 31 | fmt.Println("End") 32 | } 33 | 34 | func TestSquareWithAssert(t *testing.T) { 35 | inputs := [...]int{1, 2, 3} 36 | expected := [...]int{1, 4, 9} 37 | for i := 0; i < len(inputs); i++ { 38 | ret := square(inputs[i]) 39 | assert.Equal(t, expected[i], ret) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/ch49/gc_friendly/passing_ref/pass_array_test.go: -------------------------------------------------------------------------------- 1 | package gc_friendly 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | const NumOfElems = 1000 8 | 9 | type Content struct { 10 | Detail [10000]int 11 | } 12 | 13 | func withValue(arr [NumOfElems]Content) int { 14 | // fmt.Println(&arr[2]) 15 | return 0 16 | } 17 | 18 | func withReference(arr *[NumOfElems]Content) int { 19 | //b := *arr 20 | // fmt.Println(&arr[2]) 21 | return 0 22 | } 23 | 24 | func TestFn(t *testing.T) { 25 | var arr [NumOfElems]Content 26 | //fmt.Println(&arr[2]) 27 | withValue(arr) 28 | withReference(&arr) 29 | } 30 | 31 | func BenchmarkPassingArrayWithValue(b *testing.B) { 32 | var arr [NumOfElems]Content 33 | 34 | b.ResetTimer() 35 | for i := 0; i < b.N; i++ { 36 | withValue(arr) 37 | } 38 | b.StopTimer() 39 | } 40 | 41 | func BenchmarkPassingArrayWithRef(b *testing.B) { 42 | var arr [NumOfElems]Content 43 | 44 | b.ResetTimer() 45 | for i := 0; i < b.N; i++ { 46 | withReference(&arr) 47 | } 48 | b.StopTimer() 49 | } 50 | -------------------------------------------------------------------------------- /code/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 | 11 | counter := 0 12 | for i := 0; i < 5000; i++ { 13 | go func() { 14 | counter++ 15 | }() 16 | } 17 | time.Sleep(1 * time.Second) 18 | t.Logf("counter = %d", counter) 19 | 20 | } 21 | 22 | func TestCounterThreadSafe(t *testing.T) { 23 | var mut sync.Mutex 24 | counter := 0 25 | for i := 0; i < 5000; i++ { 26 | go func() { 27 | defer func() { 28 | mut.Unlock() 29 | }() 30 | mut.Lock() 31 | counter++ 32 | }() 33 | } 34 | time.Sleep(1 * time.Second) 35 | t.Logf("counter = %d", counter) 36 | 37 | } 38 | 39 | func TestCounterWaitGroup(t *testing.T) { 40 | var mut sync.Mutex 41 | var wg sync.WaitGroup 42 | counter := 0 43 | for i := 0; i < 5000; i++ { 44 | wg.Add(1) 45 | go func() { 46 | defer func() { 47 | mut.Unlock() 48 | }() 49 | mut.Lock() 50 | counter++ 51 | wg.Done() 52 | }() 53 | } 54 | wg.Wait() 55 | t.Logf("counter = %d", counter) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /code/ch11/encapsulation/encap_test.go: -------------------------------------------------------------------------------- 1 | package encap 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 (e *Employee) String() string { 16 | // fmt.Printf("Address is %x", unsafe.Pointer(&e.Name)) 17 | // return fmt.Sprintf("ID:%s/Name:%s/Age:%d", e.Id, e.Name, e.Age) 18 | // } 19 | 20 | func (e Employee) String() string { 21 | fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) 22 | return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age) 23 | } 24 | 25 | func TestCreateEmployeeObj(t *testing.T) { 26 | e := Employee{"0", "Bob", 20} 27 | e1 := Employee{Name: "Mike", Age: 30} 28 | e2 := new(Employee) //返回指针 29 | e2.Id = "2" 30 | e2.Age = 22 31 | e2.Name = "Rose" 32 | t.Log(e) 33 | t.Log(e1) 34 | t.Log(e1.Id) 35 | t.Log(e2) 36 | t.Logf("e is %T", e) 37 | t.Logf("e2 is %T", e2) 38 | } 39 | 40 | func TestStructOperations(t *testing.T) { 41 | e := Employee{"0", "Bob", 20} 42 | fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name)) 43 | t.Log(e.String()) 44 | } 45 | -------------------------------------------------------------------------------- /code/ch25/until_all_done/until_all_done_test.go: -------------------------------------------------------------------------------- 1 | package util_all_done 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", id) 13 | } 14 | 15 | func FirstResponse() 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 AllResponse() string { 28 | numOfRunner := 10 29 | ch := make(chan string, numOfRunner) 30 | for i := 0; i < numOfRunner; i++ { 31 | go func(i int) { 32 | ret := runTask(i) 33 | ch <- ret 34 | }(i) 35 | } 36 | finalRet := "" 37 | for j := 0; j < numOfRunner; j++ { 38 | finalRet += <-ch + "\n" 39 | } 40 | return finalRet 41 | } 42 | 43 | func TestFirstResponse(t *testing.T) { 44 | t.Log("Before:", runtime.NumGoroutine()) 45 | t.Log(AllResponse()) 46 | time.Sleep(time.Second * 1) 47 | t.Log("After:", runtime.NumGoroutine()) 48 | 49 | } 50 | -------------------------------------------------------------------------------- /code/ch10/func/func_test.go: -------------------------------------------------------------------------------- 1 | package fn_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 | fmt.Println("time spent:", time.Since(start).Seconds()) 19 | return ret 20 | } 21 | } 22 | 23 | func slowFun(op int) int { 24 | time.Sleep(time.Second * 1) 25 | return op 26 | } 27 | 28 | func TestFn(t *testing.T) { 29 | a, _ := returnMultiValues() 30 | t.Log(a) 31 | tsSF := timeSpent(slowFun) 32 | t.Log(tsSF(10)) 33 | } 34 | 35 | func Sum(ops ...int) int { 36 | ret := 0 37 | for _, op := range ops { 38 | ret += op 39 | } 40 | return ret 41 | } 42 | 43 | func TestVarParam(t *testing.T) { 44 | t.Log(Sum(1, 2, 3, 4)) 45 | t.Log(Sum(1, 2, 3, 4, 5)) 46 | } 47 | 48 | func Clear() { 49 | fmt.Println("Clear resources.") 50 | } 51 | 52 | func TestDefer(t *testing.T) { 53 | defer Clear() 54 | fmt.Println("Start") 55 | panic("err") 56 | } 57 | -------------------------------------------------------------------------------- /code/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[2]) 17 | s2 = append(s2, 1) 18 | t.Log(s2[0], s2[1], s2[2], s2[3]) 19 | t.Log(len(s2), cap(s2)) 20 | } 21 | 22 | func TestSliceGrowing(t *testing.T) { 23 | s := []int{} 24 | for i := 0; i < 10; i++ { 25 | s = append(s, i) 26 | t.Log(len(s), cap(s)) 27 | } 28 | } 29 | 30 | func TestSliceShareMemory(t *testing.T) { 31 | year := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 32 | "Oct", "Nov", "Dec"} 33 | Q2 := year[3:6] 34 | t.Log(Q2, len(Q2), cap(Q2)) 35 | summer := year[5:8] 36 | t.Log(summer, len(summer), cap(summer)) 37 | summer[0] = "Unknow" 38 | t.Log(Q2) 39 | t.Log(year) 40 | } 41 | 42 | func TestSliceComparing(t *testing.T) { 43 | a := []int{1, 2, 3, 4} 44 | b := []int{1, 2, 3, 4} 45 | // if a == b { //切片只能和nil比较 46 | // t.Log("equal") 47 | // } 48 | t.Log(a, b) 49 | } 50 | -------------------------------------------------------------------------------- /code/ch50/concat_string_test.go: -------------------------------------------------------------------------------- 1 | package concat_string 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 idx := 0; idx < b.N; idx++ { 16 | var s string 17 | for i := 0; i < numbers; i++ { 18 | s = fmt.Sprintf("%v%v", s, i) 19 | } 20 | } 21 | b.StopTimer() 22 | } 23 | 24 | func BenchmarkStringBuilder(b *testing.B) { 25 | b.ResetTimer() 26 | for idx := 0; idx < b.N; idx++ { 27 | var builder strings.Builder 28 | for i := 0; i < numbers; i++ { 29 | builder.WriteString(strconv.Itoa(i)) 30 | 31 | } 32 | _ = builder.String() 33 | } 34 | b.StopTimer() 35 | } 36 | 37 | func BenchmarkBytesBuf(b *testing.B) { 38 | b.ResetTimer() 39 | for idx := 0; idx < b.N; idx++ { 40 | var buf bytes.Buffer 41 | for i := 0; i < numbers; i++ { 42 | buf.WriteString(strconv.Itoa(i)) 43 | } 44 | _ = buf.String() 45 | } 46 | b.StopTimer() 47 | } 48 | 49 | func BenchmarkStringAdd(b *testing.B) { 50 | b.ResetTimer() 51 | for idx := 0; idx < b.N; idx++ { 52 | var s string 53 | for i := 0; i < numbers; i++ { 54 | s += strconv.Itoa(i) 55 | } 56 | 57 | } 58 | b.StopTimer() 59 | } 60 | -------------------------------------------------------------------------------- /code/ch35/benchmark/concat_string_test.go: -------------------------------------------------------------------------------- 1 | package benchmark_test 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestConcatStringByAdd(t *testing.T) { 11 | assert := assert.New(t) 12 | elems := []string{"1", "2", "3", "4", "5"} 13 | ret := "" 14 | for _, elem := range elems { 15 | ret += elem 16 | } 17 | assert.Equal("12345", ret) 18 | } 19 | 20 | func TestConcatStringByBytesBuffer(t *testing.T) { 21 | assert := assert.New(t) 22 | var buf bytes.Buffer 23 | elems := []string{"1", "2", "3", "4", "5"} 24 | for _, elem := range elems { 25 | buf.WriteString(elem) 26 | 27 | } 28 | assert.Equal("12345", buf.String()) 29 | } 30 | 31 | func BenchmarkConcatStringByAdd(b *testing.B) { 32 | 33 | elems := []string{"1", "2", "3", "4", "5"} 34 | b.ResetTimer() 35 | for i := 0; i < b.N; i++ { 36 | ret := "" 37 | for _, elem := range elems { 38 | ret += elem 39 | } 40 | } 41 | b.StopTimer() 42 | } 43 | 44 | func BenchmarkConcatStringByBytesBuffer(b *testing.B) { 45 | elems := []string{"1", "2", "3", "4", "5"} 46 | b.ResetTimer() 47 | for i := 0; i < b.N; i++ { 48 | var buf bytes.Buffer 49 | 50 | for _, elem := range elems { 51 | buf.WriteString(elem) 52 | 53 | } 54 | } 55 | b.StopTimer() 56 | 57 | } 58 | -------------------------------------------------------------------------------- /code/ch49/gc_friendly/auto_growing/auto_growing_test.go: -------------------------------------------------------------------------------- 1 | package gc_friendly 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, 100000) 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, 800000) 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 | -------------------------------------------------------------------------------- /code/ch48/lock/lock_test.go: -------------------------------------------------------------------------------- 1 | package lock_test 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 | -------------------------------------------------------------------------------- /code/ch45/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 | -------------------------------------------------------------------------------- /code/ch48/maps/map_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | import ( 4 | "strconv" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | const ( 10 | NumOfReader = 100 11 | NumOfWriter = 10 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 | -------------------------------------------------------------------------------- /code/ch39/unsafe_programming/unsafe_test.go: -------------------------------------------------------------------------------- 1 | package unsafe_test 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 | // The cases is suitable for unsafe 25 | type MyInt int 26 | 27 | //合理的类型转换 28 | func TestConvert(t *testing.T) { 29 | a := []int{1, 2, 3, 4} 30 | b := *(*[]MyInt)(unsafe.Pointer(&a)) 31 | t.Log(b) 32 | } 33 | 34 | //原子类型操作 35 | func TestAtomic(t *testing.T) { 36 | var shareBufPtr unsafe.Pointer 37 | writeDataFn := func() { 38 | data := []int{} 39 | for i := 0; i < 100; i++ { 40 | data = append(data, i) 41 | } 42 | atomic.StorePointer(&shareBufPtr, unsafe.Pointer(&data)) 43 | } 44 | readDataFn := func() { 45 | data := atomic.LoadPointer(&shareBufPtr) 46 | fmt.Println(data, *(*[]int)(data)) 47 | } 48 | var wg sync.WaitGroup 49 | writeDataFn() 50 | for i := 0; i < 10; i++ { 51 | wg.Add(1) 52 | go func() { 53 | for i := 0; i < 10; i++ { 54 | writeDataFn() 55 | time.Sleep(time.Microsecond * 100) 56 | } 57 | wg.Done() 58 | }() 59 | wg.Add(1) 60 | go func() { 61 | for i := 0; i < 10; i++ { 62 | readDataFn() 63 | time.Sleep(time.Microsecond * 100) 64 | } 65 | wg.Done() 66 | }() 67 | } 68 | wg.Wait() 69 | } 70 | -------------------------------------------------------------------------------- /code/ch43/easyjson/embedded_json_test.go: -------------------------------------------------------------------------------- 1 | package jsontest 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 | -------------------------------------------------------------------------------- /code/ch47/optmization.go: -------------------------------------------------------------------------------- 1 | package profiling 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | func createRequest() string { 10 | payload := make([]int, 100, 100) 11 | for i := 0; i < 100; i++ { 12 | payload[i] = i 13 | } 14 | req := Request{"demo_transaction", payload} 15 | v, err := json.Marshal(&req) 16 | if err != nil { 17 | panic(err) 18 | } 19 | return string(v) 20 | } 21 | 22 | func processRequest(reqs []string) []string { 23 | reps := []string{} 24 | for _, req := range reqs { 25 | reqObj := &Request{} 26 | reqObj.UnmarshalJSON([]byte(req)) 27 | // json.Unmarshal([]byte(req), reqObj) 28 | 29 | var buf strings.Builder 30 | for _, e := range reqObj.PayLoad { 31 | buf.WriteString(strconv.Itoa(e)) 32 | buf.WriteString(",") 33 | } 34 | repObj := &Response{reqObj.TransactionID, buf.String()} 35 | repJson, err := repObj.MarshalJSON() 36 | //repJson, err := json.Marshal(&repObj) 37 | if err != nil { 38 | panic(err) 39 | } 40 | reps = append(reps, string(repJson)) 41 | } 42 | return reps 43 | } 44 | 45 | func processRequestOld(reqs []string) []string { 46 | reps := []string{} 47 | for _, req := range reqs { 48 | reqObj := &Request{} 49 | json.Unmarshal([]byte(req), reqObj) 50 | ret := "" 51 | for _, e := range reqObj.PayLoad { 52 | ret += strconv.Itoa(e) + "," 53 | } 54 | repObj := &Response{reqObj.TransactionID, ret} 55 | repJson, err := json.Marshal(&repObj) 56 | if err != nil { 57 | panic(err) 58 | } 59 | reps = append(reps, string(repJson)) 60 | } 61 | return reps 62 | } 63 | -------------------------------------------------------------------------------- /code/ch14/error/err_test.go: -------------------------------------------------------------------------------- 1 | package err_test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strconv" 7 | "testing" 8 | ) 9 | 10 | var LessThanTwoError = errors.New("n should be not less than 2") 11 | var LargerThenHundredError = errors.New("n should be not larger than 100") 12 | 13 | func GetFibonacci(n int) ([]int, error) { 14 | if n < 2 { 15 | return nil, LessThanTwoError 16 | } 17 | if n > 100 { 18 | return nil, LargerThenHundredError 19 | } 20 | fibList := []int{1, 1} 21 | 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 | t.Error(err) 34 | } else { 35 | t.Log(v) 36 | } 37 | 38 | } 39 | 40 | func GetFibonacci1(str string) { 41 | var ( 42 | i int 43 | err error 44 | list []int 45 | ) 46 | if i, err = strconv.Atoi(str); err == nil { 47 | if list, err = GetFibonacci(i); err == nil { 48 | fmt.Println(list) 49 | } else { 50 | fmt.Println("Error", err) 51 | } 52 | } else { 53 | fmt.Println("Error", err) 54 | } 55 | } 56 | 57 | func GetFibonacci2(str string) { 58 | var ( 59 | i int 60 | err error 61 | list []int 62 | ) 63 | if i, err = strconv.Atoi(str); err != nil { 64 | fmt.Println("Error", err) 65 | return 66 | } 67 | if list, err = GetFibonacci(i); err != nil { 68 | 69 | fmt.Println("Error", err) 70 | return 71 | } 72 | fmt.Println(list) 73 | 74 | } 75 | -------------------------------------------------------------------------------- /code/ch46/tools/file/prof.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "math/rand" 6 | "os" 7 | "runtime" 8 | "runtime/pprof" 9 | "time" 10 | ) 11 | 12 | const ( 13 | col = 10000 14 | row = 10000 15 | ) 16 | 17 | func fillMatrix(m *[row][col]int) { 18 | s := rand.New(rand.NewSource(time.Now().UnixNano())) 19 | 20 | for i := 0; i < row; i++ { 21 | for j := 0; j < col; j++ { 22 | m[i][j] = s.Intn(100000) 23 | } 24 | } 25 | } 26 | 27 | func calculate(m *[row][col]int) { 28 | for i := 0; i < row; i++ { 29 | tmp := 0 30 | for j := 0; j < col; j++ { 31 | tmp += m[i][j] 32 | } 33 | } 34 | } 35 | 36 | func main() { 37 | //创建输出文件 38 | f, err := os.Create("cpu.prof") 39 | if err != nil { 40 | log.Fatal("could not create CPU profile: ", err) 41 | } 42 | 43 | // 获取系统信息 44 | if err := pprof.StartCPUProfile(f); err != nil { //监控cpu 45 | log.Fatal("could not start CPU profile: ", err) 46 | } 47 | defer pprof.StopCPUProfile() 48 | 49 | // 主逻辑区,进行一些简单的代码运算 50 | x := [row][col]int{} 51 | fillMatrix(&x) 52 | calculate(&x) 53 | 54 | f1, err := os.Create("mem.prof") 55 | if err != nil { 56 | log.Fatal("could not create memory profile: ", err) 57 | } 58 | runtime.GC() // GC,获取最新的数据信息 59 | if err := pprof.WriteHeapProfile(f1); err != nil { // 写入内存信息 60 | log.Fatal("could not write memory profile: ", err) 61 | } 62 | f1.Close() 63 | 64 | f2, err := os.Create("goroutine.prof") 65 | if err != nil { 66 | log.Fatal("could not create groutine profile: ", err) 67 | } 68 | 69 | if gProf := pprof.Lookup("goroutine"); gProf == nil { 70 | log.Fatal("could not write groutine profile: ") 71 | } else { 72 | gProf.WriteTo(f2, 0) 73 | } 74 | f2.Close() 75 | 76 | } 77 | -------------------------------------------------------------------------------- /code/ch41/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 | -------------------------------------------------------------------------------- /code/ch37/reflect/reflect_test.go: -------------------------------------------------------------------------------- 1 | package reflect_test 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("Integer") 22 | default: 23 | fmt.Println("Unknown", t) 24 | } 25 | } 26 | 27 | func TestBasicType(t *testing.T) { 28 | var f float64 = 12 29 | CheckType(&f) 30 | 31 | } 32 | 33 | func TestDeepEqual(t *testing.T) { 34 | a := map[int]string{1: "one", 2: "two", 3: "three"} 35 | b := map[int]string{1: "one", 2: "two", 3: "three"} 36 | // t.Log(a == b) 37 | t.Log("a==b?", reflect.DeepEqual(a, b)) 38 | 39 | s1 := []int{1, 2, 3} 40 | s2 := []int{1, 2, 3} 41 | s3 := []int{2, 3, 1} 42 | 43 | t.Log("s1 == s2?", reflect.DeepEqual(s1, s2)) 44 | t.Log("s1 == s3?", reflect.DeepEqual(s1, s3)) 45 | 46 | c1 := Customer{"1", "Mike", 40} 47 | c2 := Customer{"1", "Mike", 40} 48 | fmt.Println(c1 == c2) 49 | fmt.Println(reflect.DeepEqual(c1, c2)) 50 | } 51 | 52 | type Employee struct { 53 | EmployeeID string 54 | Name string `format:"normal"` 55 | Age int 56 | } 57 | 58 | func (e *Employee) UpdateAge(newVal int) { 59 | e.Age = newVal 60 | } 61 | 62 | type Customer struct { 63 | CookieID string 64 | Name string 65 | Age int 66 | } 67 | 68 | func TestInvokeByName(t *testing.T) { 69 | e := &Employee{"1", "Mike", 30} 70 | //按名字获取成员 71 | t.Logf("Name: value(%[1]v), Type(%[1]T) ", reflect.ValueOf(*e).FieldByName("Name")) 72 | if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok { 73 | t.Error("Failed to get 'Name' field.") 74 | } else { 75 | t.Log("Tag:format", nameField.Tag.Get("format")) 76 | } 77 | reflect.ValueOf(e).MethodByName("UpdateAge"). 78 | Call([]reflect.Value{reflect.ValueOf(1)}) 79 | t.Log("Updated Age:", e) 80 | } 81 | -------------------------------------------------------------------------------- /code/ch38/flexible_reflect_test.go: -------------------------------------------------------------------------------- 1 | package flexible_reflect 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestDeepEqual(t *testing.T) { 10 | a := map[int]string{1: "one", 2: "two", 3: "three"} 11 | b := map[int]string{1: "one", 2: "two", 3: "three"} 12 | //t.Log(a == b) 13 | t.Log(reflect.DeepEqual(a, b)) 14 | 15 | s1 := []int{1, 2, 3} 16 | s2 := []int{1, 2, 3} 17 | s3 := []int{2, 3, 1} 18 | t.Log("s1 == s2?", reflect.DeepEqual(s1, s2)) 19 | t.Log("s1 == s3?", reflect.DeepEqual(s1, s3)) 20 | 21 | } 22 | 23 | type Employee struct { 24 | EmployeeID string 25 | Name string `format:"normal"` 26 | Age int 27 | } 28 | 29 | func (e *Employee) UpdateAge(newVal int) { 30 | e.Age = newVal 31 | } 32 | 33 | type Customer struct { 34 | CookieID string 35 | Name string 36 | Age int 37 | } 38 | 39 | func fillBySettings(st interface{}, settings map[string]interface{}) error { 40 | 41 | // func (v Value) Elem() Value 42 | // Elem returns the value that the interface v contains or that the pointer v points to. 43 | // It panics if v's Kind is not Interface or Ptr. 44 | // It returns the zero Value if v is nil. 45 | 46 | if reflect.TypeOf(st).Kind() != reflect.Ptr { 47 | return errors.New("the first param should be a pointer to the struct type.") 48 | } 49 | // Elem() 获取指针指向的值 50 | if reflect.TypeOf(st).Elem().Kind() != reflect.Struct { 51 | return errors.New("the first param should be a pointer to the struct type.") 52 | } 53 | 54 | if settings == nil { 55 | return errors.New("settings is nil.") 56 | } 57 | 58 | var ( 59 | field reflect.StructField 60 | ok bool 61 | ) 62 | 63 | for k, v := range settings { 64 | if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok { 65 | continue 66 | } 67 | if field.Type == reflect.TypeOf(v) { 68 | vstr := reflect.ValueOf(st) 69 | vstr = vstr.Elem() 70 | vstr.FieldByName(k).Set(reflect.ValueOf(v)) 71 | } 72 | 73 | } 74 | return nil 75 | } 76 | 77 | func TestFillNameAndAge(t *testing.T) { 78 | settings := map[string]interface{}{"Name": "Mike", "Age": 30} 79 | e := Employee{} 80 | if err := fillBySettings(&e, settings); err != nil { 81 | t.Fatal(err) 82 | } 83 | t.Log(e) 84 | c := new(Customer) 85 | if err := fillBySettings(c, settings); err != nil { 86 | t.Fatal(err) 87 | } 88 | t.Log(*c) 89 | } 90 | -------------------------------------------------------------------------------- /code/ch41/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 | -------------------------------------------------------------------------------- /code/ch47/structs_easyjson.go: -------------------------------------------------------------------------------- 1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. 2 | 3 | package profiling 4 | 5 | import ( 6 | json "encoding/json" 7 | easyjson "github.com/mailru/easyjson" 8 | jlexer "github.com/mailru/easyjson/jlexer" 9 | jwriter "github.com/mailru/easyjson/jwriter" 10 | ) 11 | 12 | // suppress unused package warning 13 | var ( 14 | _ *json.RawMessage 15 | _ *jlexer.Lexer 16 | _ *jwriter.Writer 17 | _ easyjson.Marshaler 18 | ) 19 | 20 | func easyjson6a975c40DecodeCh47(in *jlexer.Lexer, out *Response) { 21 | isTopLevel := in.IsStart() 22 | if in.IsNull() { 23 | if isTopLevel { 24 | in.Consumed() 25 | } 26 | in.Skip() 27 | return 28 | } 29 | in.Delim('{') 30 | for !in.IsDelim('}') { 31 | key := in.UnsafeString() 32 | in.WantColon() 33 | if in.IsNull() { 34 | in.Skip() 35 | in.WantComma() 36 | continue 37 | } 38 | switch key { 39 | case "transaction_id": 40 | out.TransactionID = string(in.String()) 41 | case "exp": 42 | out.Expression = string(in.String()) 43 | default: 44 | in.SkipRecursive() 45 | } 46 | in.WantComma() 47 | } 48 | in.Delim('}') 49 | if isTopLevel { 50 | in.Consumed() 51 | } 52 | } 53 | func easyjson6a975c40EncodeCh47(out *jwriter.Writer, in Response) { 54 | out.RawByte('{') 55 | first := true 56 | _ = first 57 | { 58 | const prefix string = ",\"transaction_id\":" 59 | if first { 60 | first = false 61 | out.RawString(prefix[1:]) 62 | } else { 63 | out.RawString(prefix) 64 | } 65 | out.String(string(in.TransactionID)) 66 | } 67 | { 68 | const prefix string = ",\"exp\":" 69 | if first { 70 | first = false 71 | out.RawString(prefix[1:]) 72 | } else { 73 | out.RawString(prefix) 74 | } 75 | out.String(string(in.Expression)) 76 | } 77 | out.RawByte('}') 78 | } 79 | 80 | // MarshalJSON supports json.Marshaler interface 81 | func (v Response) MarshalJSON() ([]byte, error) { 82 | w := jwriter.Writer{} 83 | easyjson6a975c40EncodeCh47(&w, v) 84 | return w.Buffer.BuildBytes(), w.Error 85 | } 86 | 87 | // MarshalEasyJSON supports easyjson.Marshaler interface 88 | func (v Response) MarshalEasyJSON(w *jwriter.Writer) { 89 | easyjson6a975c40EncodeCh47(w, v) 90 | } 91 | 92 | // UnmarshalJSON supports json.Unmarshaler interface 93 | func (v *Response) UnmarshalJSON(data []byte) error { 94 | r := jlexer.Lexer{Data: data} 95 | easyjson6a975c40DecodeCh47(&r, v) 96 | return r.Error() 97 | } 98 | 99 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 100 | func (v *Response) UnmarshalEasyJSON(l *jlexer.Lexer) { 101 | easyjson6a975c40DecodeCh47(l, v) 102 | } 103 | func easyjson6a975c40DecodeCh471(in *jlexer.Lexer, out *Request) { 104 | isTopLevel := in.IsStart() 105 | if in.IsNull() { 106 | if isTopLevel { 107 | in.Consumed() 108 | } 109 | in.Skip() 110 | return 111 | } 112 | in.Delim('{') 113 | for !in.IsDelim('}') { 114 | key := in.UnsafeString() 115 | in.WantColon() 116 | if in.IsNull() { 117 | in.Skip() 118 | in.WantComma() 119 | continue 120 | } 121 | switch key { 122 | case "transaction_id": 123 | out.TransactionID = string(in.String()) 124 | case "payload": 125 | if in.IsNull() { 126 | in.Skip() 127 | out.PayLoad = nil 128 | } else { 129 | in.Delim('[') 130 | if out.PayLoad == nil { 131 | if !in.IsDelim(']') { 132 | out.PayLoad = make([]int, 0, 8) 133 | } else { 134 | out.PayLoad = []int{} 135 | } 136 | } else { 137 | out.PayLoad = (out.PayLoad)[:0] 138 | } 139 | for !in.IsDelim(']') { 140 | var v1 int 141 | v1 = int(in.Int()) 142 | out.PayLoad = append(out.PayLoad, v1) 143 | in.WantComma() 144 | } 145 | in.Delim(']') 146 | } 147 | default: 148 | in.SkipRecursive() 149 | } 150 | in.WantComma() 151 | } 152 | in.Delim('}') 153 | if isTopLevel { 154 | in.Consumed() 155 | } 156 | } 157 | func easyjson6a975c40EncodeCh471(out *jwriter.Writer, in Request) { 158 | out.RawByte('{') 159 | first := true 160 | _ = first 161 | { 162 | const prefix string = ",\"transaction_id\":" 163 | if first { 164 | first = false 165 | out.RawString(prefix[1:]) 166 | } else { 167 | out.RawString(prefix) 168 | } 169 | out.String(string(in.TransactionID)) 170 | } 171 | { 172 | const prefix string = ",\"payload\":" 173 | if first { 174 | first = false 175 | out.RawString(prefix[1:]) 176 | } else { 177 | out.RawString(prefix) 178 | } 179 | if in.PayLoad == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { 180 | out.RawString("null") 181 | } else { 182 | out.RawByte('[') 183 | for v2, v3 := range in.PayLoad { 184 | if v2 > 0 { 185 | out.RawByte(',') 186 | } 187 | out.Int(int(v3)) 188 | } 189 | out.RawByte(']') 190 | } 191 | } 192 | out.RawByte('}') 193 | } 194 | 195 | // MarshalJSON supports json.Marshaler interface 196 | func (v Request) MarshalJSON() ([]byte, error) { 197 | w := jwriter.Writer{} 198 | easyjson6a975c40EncodeCh471(&w, v) 199 | return w.Buffer.BuildBytes(), w.Error 200 | } 201 | 202 | // MarshalEasyJSON supports easyjson.Marshaler interface 203 | func (v Request) MarshalEasyJSON(w *jwriter.Writer) { 204 | easyjson6a975c40EncodeCh471(w, v) 205 | } 206 | 207 | // UnmarshalJSON supports json.Unmarshaler interface 208 | func (v *Request) UnmarshalJSON(data []byte) error { 209 | r := jlexer.Lexer{Data: data} 210 | easyjson6a975c40DecodeCh471(&r, v) 211 | return r.Error() 212 | } 213 | 214 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 215 | func (v *Request) UnmarshalEasyJSON(l *jlexer.Lexer) { 216 | easyjson6a975c40DecodeCh471(l, v) 217 | } 218 | -------------------------------------------------------------------------------- /code/ch43/easyjson/struct_def_easyjson.go: -------------------------------------------------------------------------------- 1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. 2 | 3 | package jsontest 4 | 5 | import ( 6 | json "encoding/json" 7 | easyjson "github.com/mailru/easyjson" 8 | jlexer "github.com/mailru/easyjson/jlexer" 9 | jwriter "github.com/mailru/easyjson/jwriter" 10 | ) 11 | 12 | // suppress unused package warning 13 | var ( 14 | _ *json.RawMessage 15 | _ *jlexer.Lexer 16 | _ *jwriter.Writer 17 | _ easyjson.Marshaler 18 | ) 19 | 20 | func easyjson7c82d03DecodeCh43Easyjson(in *jlexer.Lexer, out *JobInfo) { 21 | isTopLevel := in.IsStart() 22 | if in.IsNull() { 23 | if isTopLevel { 24 | in.Consumed() 25 | } 26 | in.Skip() 27 | return 28 | } 29 | in.Delim('{') 30 | for !in.IsDelim('}') { 31 | key := in.UnsafeString() 32 | in.WantColon() 33 | if in.IsNull() { 34 | in.Skip() 35 | in.WantComma() 36 | continue 37 | } 38 | switch key { 39 | case "skills": 40 | if in.IsNull() { 41 | in.Skip() 42 | out.Skills = nil 43 | } else { 44 | in.Delim('[') 45 | if out.Skills == nil { 46 | if !in.IsDelim(']') { 47 | out.Skills = make([]string, 0, 4) 48 | } else { 49 | out.Skills = []string{} 50 | } 51 | } else { 52 | out.Skills = (out.Skills)[:0] 53 | } 54 | for !in.IsDelim(']') { 55 | var v1 string 56 | v1 = string(in.String()) 57 | out.Skills = append(out.Skills, v1) 58 | in.WantComma() 59 | } 60 | in.Delim(']') 61 | } 62 | default: 63 | in.SkipRecursive() 64 | } 65 | in.WantComma() 66 | } 67 | in.Delim('}') 68 | if isTopLevel { 69 | in.Consumed() 70 | } 71 | } 72 | func easyjson7c82d03EncodeCh43Easyjson(out *jwriter.Writer, in JobInfo) { 73 | out.RawByte('{') 74 | first := true 75 | _ = first 76 | { 77 | const prefix string = ",\"skills\":" 78 | if first { 79 | first = false 80 | out.RawString(prefix[1:]) 81 | } else { 82 | out.RawString(prefix) 83 | } 84 | if in.Skills == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 { 85 | out.RawString("null") 86 | } else { 87 | out.RawByte('[') 88 | for v2, v3 := range in.Skills { 89 | if v2 > 0 { 90 | out.RawByte(',') 91 | } 92 | out.String(string(v3)) 93 | } 94 | out.RawByte(']') 95 | } 96 | } 97 | out.RawByte('}') 98 | } 99 | 100 | // MarshalJSON supports json.Marshaler interface 101 | func (v JobInfo) MarshalJSON() ([]byte, error) { 102 | w := jwriter.Writer{} 103 | easyjson7c82d03EncodeCh43Easyjson(&w, v) 104 | return w.Buffer.BuildBytes(), w.Error 105 | } 106 | 107 | // MarshalEasyJSON supports easyjson.Marshaler interface 108 | func (v JobInfo) MarshalEasyJSON(w *jwriter.Writer) { 109 | easyjson7c82d03EncodeCh43Easyjson(w, v) 110 | } 111 | 112 | // UnmarshalJSON supports json.Unmarshaler interface 113 | func (v *JobInfo) UnmarshalJSON(data []byte) error { 114 | r := jlexer.Lexer{Data: data} 115 | easyjson7c82d03DecodeCh43Easyjson(&r, v) 116 | return r.Error() 117 | } 118 | 119 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 120 | func (v *JobInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { 121 | easyjson7c82d03DecodeCh43Easyjson(l, v) 122 | } 123 | func easyjson7c82d03DecodeCh43Easyjson1(in *jlexer.Lexer, out *Employee) { 124 | isTopLevel := in.IsStart() 125 | if in.IsNull() { 126 | if isTopLevel { 127 | in.Consumed() 128 | } 129 | in.Skip() 130 | return 131 | } 132 | in.Delim('{') 133 | for !in.IsDelim('}') { 134 | key := in.UnsafeString() 135 | in.WantColon() 136 | if in.IsNull() { 137 | in.Skip() 138 | in.WantComma() 139 | continue 140 | } 141 | switch key { 142 | case "basic_info": 143 | (out.BasicInfo).UnmarshalEasyJSON(in) 144 | case "job_info": 145 | (out.JobInfo).UnmarshalEasyJSON(in) 146 | default: 147 | in.SkipRecursive() 148 | } 149 | in.WantComma() 150 | } 151 | in.Delim('}') 152 | if isTopLevel { 153 | in.Consumed() 154 | } 155 | } 156 | func easyjson7c82d03EncodeCh43Easyjson1(out *jwriter.Writer, in Employee) { 157 | out.RawByte('{') 158 | first := true 159 | _ = first 160 | { 161 | const prefix string = ",\"basic_info\":" 162 | if first { 163 | first = false 164 | out.RawString(prefix[1:]) 165 | } else { 166 | out.RawString(prefix) 167 | } 168 | (in.BasicInfo).MarshalEasyJSON(out) 169 | } 170 | { 171 | const prefix string = ",\"job_info\":" 172 | if first { 173 | first = false 174 | out.RawString(prefix[1:]) 175 | } else { 176 | out.RawString(prefix) 177 | } 178 | (in.JobInfo).MarshalEasyJSON(out) 179 | } 180 | out.RawByte('}') 181 | } 182 | 183 | // MarshalJSON supports json.Marshaler interface 184 | func (v Employee) MarshalJSON() ([]byte, error) { 185 | w := jwriter.Writer{} 186 | easyjson7c82d03EncodeCh43Easyjson1(&w, v) 187 | return w.Buffer.BuildBytes(), w.Error 188 | } 189 | 190 | // MarshalEasyJSON supports easyjson.Marshaler interface 191 | func (v Employee) MarshalEasyJSON(w *jwriter.Writer) { 192 | easyjson7c82d03EncodeCh43Easyjson1(w, v) 193 | } 194 | 195 | // UnmarshalJSON supports json.Unmarshaler interface 196 | func (v *Employee) UnmarshalJSON(data []byte) error { 197 | r := jlexer.Lexer{Data: data} 198 | easyjson7c82d03DecodeCh43Easyjson1(&r, v) 199 | return r.Error() 200 | } 201 | 202 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 203 | func (v *Employee) UnmarshalEasyJSON(l *jlexer.Lexer) { 204 | easyjson7c82d03DecodeCh43Easyjson1(l, v) 205 | } 206 | func easyjson7c82d03DecodeCh43Easyjson2(in *jlexer.Lexer, out *BasicInfo) { 207 | isTopLevel := in.IsStart() 208 | if in.IsNull() { 209 | if isTopLevel { 210 | in.Consumed() 211 | } 212 | in.Skip() 213 | return 214 | } 215 | in.Delim('{') 216 | for !in.IsDelim('}') { 217 | key := in.UnsafeString() 218 | in.WantColon() 219 | if in.IsNull() { 220 | in.Skip() 221 | in.WantComma() 222 | continue 223 | } 224 | switch key { 225 | case "name": 226 | out.Name = string(in.String()) 227 | case "age": 228 | out.Age = int(in.Int()) 229 | default: 230 | in.SkipRecursive() 231 | } 232 | in.WantComma() 233 | } 234 | in.Delim('}') 235 | if isTopLevel { 236 | in.Consumed() 237 | } 238 | } 239 | func easyjson7c82d03EncodeCh43Easyjson2(out *jwriter.Writer, in BasicInfo) { 240 | out.RawByte('{') 241 | first := true 242 | _ = first 243 | { 244 | const prefix string = ",\"name\":" 245 | if first { 246 | first = false 247 | out.RawString(prefix[1:]) 248 | } else { 249 | out.RawString(prefix) 250 | } 251 | out.String(string(in.Name)) 252 | } 253 | { 254 | const prefix string = ",\"age\":" 255 | if first { 256 | first = false 257 | out.RawString(prefix[1:]) 258 | } else { 259 | out.RawString(prefix) 260 | } 261 | out.Int(int(in.Age)) 262 | } 263 | out.RawByte('}') 264 | } 265 | 266 | // MarshalJSON supports json.Marshaler interface 267 | func (v BasicInfo) MarshalJSON() ([]byte, error) { 268 | w := jwriter.Writer{} 269 | easyjson7c82d03EncodeCh43Easyjson2(&w, v) 270 | return w.Buffer.BuildBytes(), w.Error 271 | } 272 | 273 | // MarshalEasyJSON supports easyjson.Marshaler interface 274 | func (v BasicInfo) MarshalEasyJSON(w *jwriter.Writer) { 275 | easyjson7c82d03EncodeCh43Easyjson2(w, v) 276 | } 277 | 278 | // UnmarshalJSON supports json.Unmarshaler interface 279 | func (v *BasicInfo) UnmarshalJSON(data []byte) error { 280 | r := jlexer.Lexer{Data: data} 281 | easyjson7c82d03DecodeCh43Easyjson2(&r, v) 282 | return r.Error() 283 | } 284 | 285 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface 286 | func (v *BasicInfo) UnmarshalEasyJSON(l *jlexer.Lexer) { 287 | easyjson7c82d03DecodeCh43Easyjson2(l, v) 288 | } 289 | --------------------------------------------------------------------------------