├── .gitignore ├── GoExpert └── src │ ├── append │ ├── append.go │ └── append_test.go │ ├── defer │ └── defer.go │ ├── gotest │ ├── benchmark.go │ ├── benchmark_test.go │ ├── example.go │ ├── example_test.go │ ├── maintest_test.go │ ├── subbenchmark_test.go │ ├── subparallel_test.go │ ├── subunit_test.go │ ├── unit.go │ └── unit_test.go │ ├── slice │ ├── slice.go │ └── slice_test.go │ ├── string │ ├── example.go │ └── example_test.go │ ├── testmod │ └── testmod.go │ ├── timer │ └── timerExample.go │ └── unpinned │ ├── unpinned.go │ └── unpinned_test.go ├── Makefile ├── README.md ├── chan ├── chan.go ├── chan_test.go ├── exam.go └── exam_test.go ├── compare ├── compare.go ├── compare_test.go ├── uncomparable.go └── uncomparable_test.go ├── defer ├── deferexam.go └── deferexam_test.go ├── errors ├── chanerror.go ├── chanerror_test.go ├── errors.go ├── errors_test.go ├── exam.go └── exam_test.go ├── generics ├── constraint │ ├── approximation.go │ ├── approximation_test.go │ ├── arbitrary.go │ ├── arbitrary_test.go │ ├── operationbased.go │ ├── operationbased_test.go │ ├── union.go │ └── union_test.go ├── examples │ ├── mapkeys.go │ ├── mapkeys_test.go │ ├── sets.go │ ├── sets_test.go │ ├── sort.go │ └── sort_test.go ├── overall │ ├── genericfunctions.go │ ├── genericfunctions_test.go │ ├── generictypes.go │ └── generictypes_test.go └── quickstart │ └── main.go ├── go.mod ├── go.sum ├── gomock ├── mockreporter │ └── mockreporter.go └── reporter │ ├── reporter.go │ └── reporter_test.go ├── gotest └── fuzz │ ├── fuzz.go │ └── fuzz_test.go ├── iota ├── exam.go └── exam_test.go ├── map ├── exam.go ├── exam_test.go ├── map.go └── map_test.go ├── panic ├── exam.go ├── exam_test.go ├── panic.go └── panic_test.go ├── range ├── compile.go ├── exam.go ├── exam_test.go ├── range.go └── range_test.go ├── recover ├── compile.go ├── exam.go ├── exam_test.go ├── recover.go └── recover_test.go ├── reflection ├── interface.go └── interface_test.go ├── select ├── exam.go ├── exam_test.go ├── principle.go ├── principle_test.go ├── select.go └── select_test.go ├── slice ├── exam.go ├── exam_test.go ├── extend.go ├── extend_test.go ├── slice.go └── slice_test.go ├── string ├── exam.go ├── exam_test.go ├── extend.go ├── extend_test.go ├── principle.go ├── principle_test.go ├── string.go ├── string_test.go ├── strings.go └── strings_test.go ├── struct ├── exam.go ├── exam_test.go ├── promoted.go ├── promoted_test.go ├── receiver.go ├── receiver_test.go ├── struct.go ├── struct_test.go ├── tag.go └── tag_test.go ├── sugar ├── shortVariableDeclarations.go ├── variadic.go └── variadic_test.go ├── syncmap ├── demonstrate.go └── demonstrate_test.go └── trap ├── loop ├── reference.go └── reference_test.go └── loop2 ├── loop2.go └── loop2_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Output of IDEs 15 | .idea 16 | 17 | # Output of build 18 | pkg 19 | -------------------------------------------------------------------------------- /GoExpert/src/append/append.go: -------------------------------------------------------------------------------- 1 | package append 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func Validation() []error { 10 | var errs []error 11 | 12 | errs = append(errs, errors.New("error 1")) 13 | errs = append(errs, errors.New("error 2")) 14 | errs = append(errs, errors.New("error 3")) 15 | 16 | return errs 17 | } 18 | 19 | func ValidateName(name string) error { 20 | if name != "" { 21 | return nil 22 | } 23 | 24 | return errors.New("empty name") 25 | } 26 | 27 | func Validations(name string) []error { 28 | var errs []error 29 | 30 | errs = append(errs, ValidateName(name)) 31 | 32 | return errs 33 | } 34 | 35 | func foo() { 36 | errs := Validations("") 37 | 38 | if len(errs) > 0 { 39 | println(errs) 40 | os.Exit(1) 41 | } 42 | } 43 | 44 | func AppendDemo3() { 45 | x := make([]int, 0, 10) 46 | x = append(x, 1, 2, 3) 47 | y := append(x, 4) 48 | z := append(x, 5) 49 | fmt.Println(x) 50 | fmt.Println(y) 51 | fmt.Println(z) 52 | } 53 | -------------------------------------------------------------------------------- /GoExpert/src/append/append_test.go: -------------------------------------------------------------------------------- 1 | package append 2 | 3 | func ExampleAppendDemo3() { 4 | AppendDemo3() 5 | // OutPut: 6 | // [1 2 3] 7 | // [1 2 3 5] 8 | // [1 2 3 5] 9 | } 10 | -------------------------------------------------------------------------------- /GoExpert/src/defer/defer.go: -------------------------------------------------------------------------------- 1 | package deferexample 2 | 3 | import "fmt" 4 | 5 | func NoPanic() { 6 | if err := recover(); err != nil { 7 | fmt.Println("Recover success...") 8 | } 9 | } 10 | 11 | func Dived(n int) { 12 | defer NoPanic() 13 | 14 | fmt.Println(1 / n) 15 | } 16 | 17 | func IsPanic() bool { 18 | if err := recover(); err != nil { 19 | fmt.Println("Recover success...") 20 | return true 21 | } 22 | 23 | return false 24 | } 25 | 26 | func UpdateTable() { 27 | defer func() { 28 | if IsPanic() { 29 | // Rollback transaction 30 | } else { 31 | // Commit transaction 32 | } 33 | }() 34 | 35 | // Database CRUD operation... 36 | } 37 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/benchmark.go: -------------------------------------------------------------------------------- 1 | package gotest 2 | 3 | // MakeSliceWithPreAlloc 不预分配 4 | func MakeSliceWithoutAlloc() []int { 5 | var newSlice []int 6 | 7 | for i := 0; i < 100000; i++ { 8 | newSlice = append(newSlice, i) 9 | } 10 | 11 | return newSlice 12 | } 13 | 14 | // MakeSliceWithPreAlloc 通过预分配Slice的存储空间构造 15 | func MakeSliceWithPreAlloc() []int { 16 | var newSlice []int 17 | 18 | newSlice = make([]int, 0, 100000) 19 | for i := 0; i < 100000; i++ { 20 | newSlice = append(newSlice, i) 21 | } 22 | 23 | return newSlice 24 | } 25 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/benchmark_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/rainbowmango/goexpertprogrammingsourcecode/GoExpert/src/gotest" 8 | ) 9 | 10 | func BenchmarkMakeSliceWithoutAlloc(b *testing.B) { 11 | for i := 0; i < b.N; i++ { 12 | gotest.MakeSliceWithoutAlloc() 13 | } 14 | } 15 | 16 | func BenchmarkMakeSliceWithPreAlloc(b *testing.B) { 17 | for i := 0; i < b.N; i++ { 18 | gotest.MakeSliceWithPreAlloc() 19 | } 20 | } 21 | 22 | func BenchmarkSetBytes(b *testing.B) { 23 | b.SetBytes(1024 * 1024) 24 | for i := 0; i < b.N; i++ { 25 | time.Sleep(1 * time.Second) // 模拟待测函数 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/example.go: -------------------------------------------------------------------------------- 1 | package gotest 2 | 3 | import "fmt" 4 | 5 | // SayHello 打印一行字符串 6 | func SayHello() { 7 | fmt.Println("Hello World") 8 | } 9 | 10 | // SayGoodbye 打印两行字符串 11 | func SayGoodbye() { 12 | fmt.Println("Hello,") 13 | fmt.Println("goodbye") 14 | } 15 | 16 | // PrintNames 打印学生姓名 17 | func PrintNames() { 18 | students := make(map[int]string, 4) 19 | students[1] = "Jim" 20 | students[2] = "Bob" 21 | students[3] = "Tom" 22 | students[4] = "Sue" 23 | for _, value := range students { 24 | fmt.Println(value) 25 | } 26 | } -------------------------------------------------------------------------------- /GoExpert/src/gotest/example_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import "github.com/rainbowmango/goexpertprogrammingsourcecode/GoExpert/src/gotest" 4 | 5 | // 检测单行输出 6 | func ExampleSayHello() { 7 | gotest.SayHello() 8 | // OutPut: Hello World 9 | } 10 | 11 | // 检测多行输出 12 | func ExampleSayGoodbye() { 13 | gotest.SayGoodbye() 14 | // OutPut: 15 | // Hello, 16 | // goodbye 17 | } 18 | 19 | // 检测乱序输出 20 | func ExamplePrintNames() { 21 | gotest.PrintNames() 22 | // Unordered output: 23 | // Jim 24 | // Bob 25 | // Tom 26 | // Sue 27 | } 28 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/maintest_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "testing" 5 | "os" 6 | ) 7 | 8 | // TestMain 用于主动执行各种测试,可以测试前后做setup和tear-down操作 9 | func TestMain(m *testing.M) { 10 | println("TestMain setup.") 11 | 12 | retCode := m.Run() // 执行测试,包括单元测试、性能测试和示例测试 13 | 14 | println("TestMain tear-down.") 15 | os.Exit(retCode) 16 | } 17 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/subbenchmark_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/rainbowmango/goexpertprogrammingsourcecode/GoExpert/src/gotest" 7 | ) 8 | 9 | func benchSub1(b *testing.B) { 10 | for i := 0; i < b.N; i++ { 11 | gotest.MakeSliceWithoutAlloc() 12 | } 13 | } 14 | 15 | func benchSub2(b *testing.B) { 16 | for i := 0; i < b.N; i++ { 17 | gotest.MakeSliceWithoutAlloc() 18 | } 19 | } 20 | 21 | func benchSub3(b *testing.B) { 22 | for i := 0; i < b.N; i++ { 23 | gotest.MakeSliceWithoutAlloc() 24 | } 25 | } 26 | 27 | func BenchmarkSub(b *testing.B) { 28 | b.Run("A=1", benchSub1) 29 | b.Run("A=2", benchSub2) 30 | b.Run("B=1", benchSub3) 31 | } 32 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/subparallel_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | // 并发子测试,无实际测试工作,仅用于演示 9 | func parallelTest1(t *testing.T) { 10 | t.Parallel() 11 | time.Sleep(3 * time.Second) 12 | // do some testing 13 | } 14 | 15 | // 并发子测试,无实际测试工作,仅用于演示 16 | func parallelTest2(t *testing.T) { 17 | t.Parallel() 18 | time.Sleep(2 * time.Second) 19 | // do some testing 20 | } 21 | 22 | // 并发子测试,无实际测试工作,仅用于演示 23 | func parallelTest3(t *testing.T) { 24 | t.Parallel() 25 | time.Sleep(1 * time.Second) 26 | // do some testing 27 | } 28 | 29 | // TestSubParallel 通过把多个子测试放到一个组中并发执行,同时多个子测试可以共享setup和tear-down 30 | func TestSubParallel(t *testing.T) { 31 | // setup 32 | t.Logf("Setup") 33 | 34 | t.Run("group", func(t *testing.T) { 35 | t.Run("Test1", parallelTest1) 36 | t.Run("Test2", parallelTest2) 37 | t.Run("Test3", parallelTest3) 38 | }) 39 | 40 | // tear down 41 | t.Logf("teardown") 42 | } 43 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/subunit_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/rainbowmango/goexpertprogrammingsourcecode/GoExpert/src/gotest" 7 | ) 8 | 9 | // sub1 为子测试,只做加法测试 10 | func sub1(t *testing.T) { 11 | var a = 1 12 | var b = 2 13 | var expected = 3 14 | 15 | actual := gotest.Add(a, b) 16 | if actual != expected { 17 | t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected) 18 | } 19 | } 20 | 21 | // sub2 为子测试,只做加法测试 22 | func sub2(t *testing.T) { 23 | var a = 1 24 | var b = 2 25 | var expected = 3 26 | 27 | actual := gotest.Add(a, b) 28 | if actual != expected { 29 | t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected) 30 | } 31 | } 32 | 33 | // sub3 为子测试,只做加法测试 34 | func sub3(t *testing.T) { 35 | var a = 1 36 | var b = 2 37 | var expected = 3 38 | 39 | actual := gotest.Add(a, b) 40 | if actual != expected { 41 | t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected) 42 | } 43 | } 44 | 45 | // TestSub 内部调用sub1、sub2和sub3三个子测试 46 | func TestSub(t *testing.T) { 47 | // setup code 48 | 49 | t.Run("A=1", sub1) 50 | t.Run("A=2", sub2) 51 | t.Run("B=1", sub3) 52 | 53 | // tear-down code 54 | } 55 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/unit.go: -------------------------------------------------------------------------------- 1 | package gotest 2 | 3 | // Add 方法用于演示go test使用 4 | func Add(a int, b int) int { 5 | return a + b 6 | } 7 | -------------------------------------------------------------------------------- /GoExpert/src/gotest/unit_test.go: -------------------------------------------------------------------------------- 1 | package gotest_test 2 | 3 | import ( 4 | "flag" 5 | "testing" 6 | 7 | "github.com/rainbowmango/goexpertprogrammingsourcecode/GoExpert/src/gotest" 8 | ) 9 | 10 | func TestAdd(t *testing.T) { 11 | var a = 1 12 | var b = 2 13 | var expected = 3 14 | 15 | actual := gotest.Add(a, b) 16 | if actual != expected { 17 | t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected) 18 | } 19 | } 20 | 21 | // TestArgs 用于演示如何解析-args参数 22 | func TestArgs(t *testing.T) { 23 | if !flag.Parsed() { 24 | flag.Parse() 25 | } 26 | 27 | argList := flag.Args() // flag.Args() 返回 -args 后面的所有参数,以切片表示,每个元素代表一个参数 28 | for _, arg := range argList { 29 | if arg == "cloud" { 30 | t.Log("Running in cloud.") 31 | } else { 32 | t.Log("Running in other mode.") 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GoExpert/src/slice/slice.go: -------------------------------------------------------------------------------- 1 | package slice 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | // simple slice expression(a[low, high]) 切取字符串时,生成的仍然为字符串 10 | func SliceString() { 11 | baseStr := "Hello World!" 12 | fmt.Printf("baseStr: %s\n", baseStr) // baseStr: Hello World! 13 | fmt.Printf("baseStr type: %s\n", reflect.TypeOf(baseStr)) // baseStr type: string 14 | 15 | newStr := baseStr[0:5] 16 | fmt.Printf("newStr: %s\n", newStr) // newStr: Hello 17 | fmt.Printf("newStr type: %v\n", reflect.TypeOf(newStr)) // newStr type: string 18 | } 19 | 20 | // simple slice expression(a[low, high]) 切取数组时,生成新的切片 21 | func SliceArray() { 22 | baseArray := [10]string{"Hello", "World"} 23 | fmt.Printf("baseArray: %s\n", baseArray) // baseArray: [Hello World ] 24 | fmt.Printf("baseArray type: %s\n", reflect.TypeOf(baseArray)) // baseArray type: [10]string 25 | 26 | newSlice := baseArray[0:5] 27 | fmt.Printf("newSlice: %v\n", newSlice) // newSlice: [Hello World ] 28 | fmt.Printf("newSlice type: %v\n", reflect.TypeOf(newSlice)) // newSlice type: []string 29 | } 30 | 31 | // simple slice expression(a[low, high]) 切取切片时,low, high取值关系为: 0 <= low <= high <= cap(a) 32 | // 特别需要注意的是low、high取值均可以超越len(a) 33 | func SliceCap() { 34 | baseSlice := make([]int, 0, 10) 35 | newSlice := baseSlice[2:5] 36 | fmt.Printf("newSlice: %v", newSlice) // newSlice: [0 0 0] 37 | } 38 | 39 | // extend slice expression(a[low, high, max])切取数组时,max用于限制新生成片的capacity。 40 | func ExtendSliceArray() { 41 | a := [5]int{1, 2, 3, 4, 5} 42 | b := a[1:4:4] 43 | fmt.Printf("cap(b): %d", cap(b)) // cap(b): 3 44 | } 45 | 46 | type Info struct { 47 | Version string // version string 48 | Time time.Time // commit time 49 | } 50 | -------------------------------------------------------------------------------- /GoExpert/src/slice/slice_test.go: -------------------------------------------------------------------------------- 1 | package slice 2 | 3 | // 检测多行输出 4 | func ExampleSliceString() { 5 | SliceString() 6 | // OutPut: 7 | // baseStr: Hello World! 8 | // baseStr type: string 9 | // newStr: Hello 10 | // newStr type: string 11 | } 12 | 13 | func ExampleSliceArray() { 14 | SliceArray() 15 | // OutPut: 16 | // baseArray: [Hello World ] 17 | // baseArray type: [10]string 18 | // newSlice: [Hello World ] 19 | // newSlice type: []string 20 | } 21 | 22 | func ExampleSliceCap() { 23 | SliceCap() 24 | // OutPut: 25 | // newSlice: [0 0 0] 26 | } 27 | 28 | func ExampleExtendSliceArray() { 29 | ExtendSliceArray() 30 | // OutPut: 31 | // cap(b): 3 32 | } 33 | -------------------------------------------------------------------------------- /GoExpert/src/string/example.go: -------------------------------------------------------------------------------- 1 | package stringExample 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | // 用于模拟string的数据结构stringStruct 9 | type dummyString struct { 10 | str unsafe.Pointer 11 | len int 12 | } 13 | 14 | // ByteSliceToString 用于测试byte切片强制转换成string 15 | func ByteSliceToString() { 16 | srcSlice := []byte{'a', 'b', 'c'} 17 | 18 | // byte slice强制转成dummyString 19 | dstString := *(*dummyString)(unsafe.Pointer(&srcSlice)) 20 | fmt.Printf("string len: %d", dstString.len) // 输出:string len 3 21 | 22 | // dummyString强制转成string 23 | realString := *(*string)(unsafe.Pointer(&dstString)) 24 | fmt.Printf("Real string: %s", realString) // 输出:Real string: abc 25 | } 26 | 27 | func GetStringBySlice(s []byte) string { 28 | return string(s) 29 | } 30 | 31 | func GetSliceByString(str string) []byte { 32 | return []byte(str) 33 | } 34 | 35 | func RunStringPackage() { 36 | ByteSliceToString() 37 | } 38 | -------------------------------------------------------------------------------- /GoExpert/src/string/example_test.go: -------------------------------------------------------------------------------- 1 | package stringExample 2 | 3 | import "testing" 4 | 5 | func TestGetSliceByString(t *testing.T) { 6 | slice := GetSliceByString("Hello,World") 7 | 8 | if string(slice) != "Hello,World" { 9 | t.Fatalf("GetSliceByString failed. expected: Hello,World, actual: %s", string(slice)) 10 | } 11 | } -------------------------------------------------------------------------------- /GoExpert/src/testmod/testmod.go: -------------------------------------------------------------------------------- 1 | package testmod 2 | 3 | import "fmt" 4 | 5 | func Hi(name string) string { 6 | return fmt.Sprintf("Hi, %s\n", name) 7 | } 8 | 9 | -------------------------------------------------------------------------------- /GoExpert/src/timer/timerExample.go: -------------------------------------------------------------------------------- 1 | package timerExample 2 | 3 | import ( 4 | "time" 5 | "log" 6 | ) 7 | 8 | // WaitChannel 用于演示timer的典型使用场景 9 | func WaitChannel(conn <-chan string) bool { 10 | timer := time.NewTimer(1 * time.Second) 11 | 12 | select { 13 | case <- conn: 14 | timer.Stop() 15 | return true 16 | case <- timer.C: // 超时 17 | println("WaitChannel timeout!") 18 | return false 19 | } 20 | } 21 | 22 | // DelayFunction 用于演示timer的使用场景: 延迟调用 23 | func DelayFunction() { 24 | timer := time.NewTimer(5 * time.Second) 25 | 26 | select { 27 | case <- timer.C: 28 | log.Println("Delayed 5s, start to do something.") 29 | } 30 | } 31 | 32 | // AfterDemo 用于演示time.After()用法 33 | func AfterDemo() { 34 | log.Println(time.Now()) 35 | <- time.After(1 * time.Second) 36 | log.Println(time.Now()) 37 | } 38 | 39 | // AfterFuncDemo 用于演示time.AfterFunc用法 40 | func AfterFuncDemo() { 41 | log.Println("AfterFuncDemo start: ", time.Now()) 42 | time.AfterFunc(1 * time.Second, func() { 43 | log.Println("AfterFuncDemo end: ", time.Now()) 44 | }) 45 | 46 | time.Sleep(2 * time.Second) // 等待协程退出 47 | } 48 | 49 | // TickerDemo 用于演示ticker基础用法 50 | func TickerDemo() { 51 | ticker := time.NewTicker(1 * time.Second) 52 | defer ticker.Stop() 53 | 54 | for range ticker.C { 55 | log.Println("Ticker tick.") 56 | } 57 | } 58 | 59 | func GetNewPassenger() string{ 60 | return "task" 61 | } 62 | 63 | func Launch([]string) { 64 | return 65 | } 66 | 67 | // TickerLaunch用于演示ticker聚合任务用法 68 | func TickerLaunch() { 69 | ticker := time.NewTicker(5 * time.Minute) 70 | maxPassenger := 30 // 每车最大装载人数 71 | passengers := make([]string, 0, maxPassenger) 72 | 73 | for { 74 | passenger := GetNewPassenger() // 获取一个新乘客 75 | if passenger != "" { 76 | passengers = append(passengers, passenger) 77 | } else { 78 | time.Sleep(1 * time.Second) 79 | } 80 | 81 | select { 82 | case <- ticker.C: // 时间到,发车 83 | Launch(passengers) 84 | passengers = []string{} 85 | default: 86 | if len(passengers) >= maxPassenger { // 时间没到,车已座满,发车 87 | Launch(passengers) 88 | passengers = []string{} 89 | } 90 | } 91 | } 92 | } 93 | 94 | func WrongTicker() { 95 | for { 96 | select { 97 | case <-time.Tick(1 * time.Second): 98 | log.Printf("Resource leak!") 99 | } 100 | } 101 | } 102 | 103 | func RunTimerPackage() { 104 | channel := make(chan string) 105 | 106 | WaitChannel(channel) 107 | DelayFunction() 108 | AfterDemo() 109 | AfterFuncDemo() 110 | 111 | //TickerDemo() 112 | 113 | //WrongTicker() 114 | } -------------------------------------------------------------------------------- /GoExpert/src/unpinned/unpinned.go: -------------------------------------------------------------------------------- 1 | package unpined 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func Process1(tasks []string) { 8 | for _, task := range tasks { 9 | // 启动协程并发处理任务 10 | go func() { 11 | fmt.Printf("Worker start process task: %s\n", task) 12 | }() 13 | } 14 | } 15 | 16 | func Process2(tasks []string) { 17 | for _, task := range tasks { 18 | // 启动协程并发处理任务 19 | go func(t string) { 20 | fmt.Printf("Worker start process task: %s\n", t) 21 | }(task) 22 | } 23 | } 24 | 25 | func Double(a int) int { 26 | return a * 2 27 | } 28 | -------------------------------------------------------------------------------- /GoExpert/src/unpinned/unpinned_test.go: -------------------------------------------------------------------------------- 1 | package unpined 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | // TestProcess1 由于引用了循环变量,导致协程打印混乱 10 | // 打印结果如下(每次执行均不一致): 11 | // E:\OpenSource\RainbowMango\GoExpertProgrammingSourceCode\GoExpert\src>go test ./unpined -v 12 | // === RUN TestProcess1 13 | // Worker start process task: 3 14 | // Worker start process task: 5 15 | // Worker start process task: 5 16 | // Worker start process task: 5 17 | // Worker start process task: 10 18 | // Worker start process task: 7 19 | // Worker start process task: 8 20 | // Worker start process task: 9 21 | // Worker start process task: 4 22 | // Worker start process task: 11 23 | // Worker start process task: 11 24 | // Worker start process task: 19 25 | // Worker start process task: 19 26 | // Worker start process task: 19 27 | // Worker start process task: 19 28 | // Worker start process task: 19 29 | // Worker start process task: 19 30 | // Worker start process task: 19 31 | // Worker start process task: 19 32 | // Worker start process task: 19 33 | // --- PASS: TestProcess1 (0.00s) 34 | // PASS 35 | // ok unpined 0.406s 36 | func TestProcess1(t *testing.T) { 37 | var tasks []string 38 | 39 | for i := 0; i < 20; i++ { 40 | tasks = append(tasks, strconv.Itoa(i)) 41 | } 42 | Process1(tasks) 43 | } 44 | 45 | func TestProcess2(t *testing.T) { 46 | var tasks []string 47 | 48 | for i := 0; i < 20; i++ { 49 | tasks = append(tasks, strconv.Itoa(i)) 50 | } 51 | Process2(tasks) 52 | } 53 | 54 | func TestDouble(t *testing.T) { 55 | var tests = []struct { 56 | name string 57 | input int 58 | expectOutput int 59 | }{ 60 | { 61 | name: "double 1 should got 2", 62 | input: 1, 63 | expectOutput: 2, 64 | }, 65 | { 66 | name: "double 2 should got 4", 67 | input: 2, 68 | expectOutput: 4, 69 | }, 70 | } 71 | 72 | for _, test := range tests { 73 | tc := test // 显式绑定,每次循环都会生成一个新的tc变量 74 | fmt.Println("tc= ", &tc) 75 | t.Run(tc.name, func(t *testing.T) { 76 | if tc.expectOutput != Double(tc.input) { 77 | t.Fatalf("expect: %d, but got: %d", tc.input, tc.expectOutput) 78 | } 79 | }) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: test 3 | test: 4 | go test --v ./... 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoExpertProgrammingSourceCode 2 | 《GO专家编程》配套源代码 3 | 4 | 5 | -------------------------------------------------------------------------------- /chan/chan.go: -------------------------------------------------------------------------------- 1 | package _chan 2 | 3 | import "fmt" 4 | 5 | func ChanInitDeclare() { 6 | var ch chan int // 声明管道 7 | fmt.Println(ch == nil) 8 | } 9 | 10 | func ChanInitMake() { 11 | ch1 := make(chan string) // 无缓冲管道 12 | ch2 := make(chan string, 5) // 带缓冲管道 13 | 14 | fmt.Println(ch1 == nil) 15 | fmt.Println(ch2 == nil) 16 | } 17 | 18 | func ChanOperator() { 19 | ch := make(chan int, 10) 20 | ch <- 1 // 数据流入管道 21 | d := <-ch // 数据流出管道 22 | fmt.Println(d) 23 | } 24 | 25 | func ChanParamRW(ch chan int) { 26 | // 管道可读写 27 | } 28 | 29 | func ChanParamR(ch <-chan int) { 30 | // 只能从管道读取数据 31 | } 32 | 33 | func ChanParamW(ch chan<- int) { 34 | // 只能向管道写入数据 35 | } 36 | 37 | // ReadChanReturnValue 用于测试读取管道时的第二个参数到底是什么含义? 38 | // 第二个参数代表是否成功读取了数据。(不代表是否关闭) 39 | func ReadChanReturnValue() { 40 | ch := make(chan int, 10) 41 | ch <- 1 42 | ch <- 2 43 | fmt.Printf("length of channel is: %d\n", len(ch)) 44 | 45 | _, ok := <-ch 46 | fmt.Printf("second return value before channel closed is: %v\n", ok) // true 47 | 48 | close(ch) 49 | 50 | _, ok = <-ch 51 | fmt.Printf("second return value after channel(have data) closed is: %v\n", ok) // true 52 | 53 | _, ok = <-ch 54 | fmt.Printf("second return value after channel(no data) closed is: %v\n", ok) // false 55 | } 56 | -------------------------------------------------------------------------------- /chan/chan_test.go: -------------------------------------------------------------------------------- 1 | package _chan 2 | 3 | func ExampleReadChanReturnValue() { 4 | ReadChanReturnValue() 5 | // Output: 6 | // length of channel is: 2 7 | // second return value before channel closed is: true 8 | // second return value after channel(have data) closed is: true 9 | // second return value after channel(no data) closed is: false 10 | } 11 | -------------------------------------------------------------------------------- /chan/exam.go: -------------------------------------------------------------------------------- 1 | package _chan 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | /* 9 | 以下可以实现互斥锁的是? 10 | - A: 11 | ``` 12 | var counter int = 0 13 | var ch = make(chan int, 1) 14 | 15 | func Worker() { 16 | ch <- 1 17 | counter++ 18 | <-ch 19 | } 20 | ``` 21 | 22 | - B: 23 | ```go 24 | var counter int = 0 25 | var ch = make(chan int) 26 | 27 | func Worker() { 28 | <-ch 29 | counter++ 30 | ch <- 1 31 | } 32 | ``` 33 | 34 | - C: 35 | ```go 36 | var counter int = 0 37 | var ch = make(chan int, 1) 38 | 39 | func Worker() { 40 | <-ch 41 | counter++ 42 | ch <- 1 43 | } 44 | ``` 45 | 46 | - D: 47 | ```go 48 | var counter int = 0 49 | var ch = make(chan int) 50 | 51 | func Worker() { 52 | ch <- 1 53 | counter++ 54 | <-ch 55 | } 56 | ``` 57 | 58 | */ 59 | var counter int = 0 60 | var ch = make(chan int, 1) 61 | var wg sync.WaitGroup 62 | 63 | func Worker() { 64 | ch <- 1 65 | counter++ 66 | wg.Done() 67 | fmt.Println(counter) 68 | <-ch 69 | } 70 | 71 | /* 72 | 下面关于管道的描述正确的是? 73 | 单选: 74 | - A: 读nil管道会panic 75 | - B: 写nil管道会panic 76 | - C: 读关闭的管道会panic 77 | - D: 写关闭的管道会panic 78 | 79 | */ 80 | 81 | // 读nil管道会阻塞 82 | func ChanReadNil() { 83 | var ch chan int 84 | d := <-ch 85 | fmt.Println(d) 86 | } 87 | 88 | // 写nil管道不会阻塞 89 | func ChanWriteNil() { 90 | var ch chan int 91 | ch <- 1 92 | } 93 | 94 | // 关闭的管道可以读 95 | func ChanReadClosed() { 96 | ch := make(chan int, 10) 97 | close(ch) 98 | d := <-ch 99 | fmt.Println(d) 100 | } 101 | 102 | // 关闭的管道不可写,否则panic 103 | // send on closed channel 104 | func ChanWriteClosed() { 105 | ch := make(chan int, 10) 106 | close(ch) 107 | ch <- 1 108 | } 109 | 110 | /* 111 | 下面函数输出什么? 112 | 113 | */ 114 | 115 | func ChanCap() { 116 | ch := make(chan int, 10) 117 | ch <- 1 118 | ch <- 2 119 | fmt.Println(len(ch)) 120 | fmt.Println(cap(ch)) 121 | } 122 | -------------------------------------------------------------------------------- /chan/exam_test.go: -------------------------------------------------------------------------------- 1 | package _chan 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func ExampleWorker() { 8 | for i := 0; i < 10; i++ { 9 | go Worker() 10 | wg.Add(1) 11 | } 12 | wg.Wait() 13 | // Output: 14 | // 1 15 | // 2 16 | // 3 17 | // 4 18 | // 5 19 | // 6 20 | // 7 21 | // 8 22 | // 9 23 | // 10 24 | } 25 | 26 | // 读nil管道会阻塞,不能添加期望值 27 | func ExampleChanReadNil() { 28 | ChanReadNil() 29 | } 30 | 31 | // 写nil管道会阻塞,不能添加期望值 32 | func ExampleChanWriteNil() { 33 | ChanWriteNil() 34 | } 35 | 36 | func ExampleChanReadClosed() { 37 | ChanReadClosed() 38 | // Output: 39 | // 0 40 | } 41 | 42 | func TestChanWriteClosed(t *testing.T) { 43 | defer func() { 44 | if err := recover(); err == nil { 45 | t.Fatal("expected panic") 46 | } 47 | }() 48 | 49 | ChanWriteClosed() 50 | } 51 | 52 | func ExampleChanCap() { 53 | ChanCap() 54 | // Output: 55 | // 2 56 | // 10 57 | } 58 | -------------------------------------------------------------------------------- /compare/compare.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | import "fmt" 4 | 5 | func StructTypeCompare() { 6 | type Student struct { 7 | name string 8 | age int 9 | } 10 | 11 | zhangsan := Student{name: "Zhang San", age: 18} 12 | lisi := Student{name: "Li Si", age: 18} 13 | 14 | fmt.Println(zhangsan == lisi) // 输出 false 15 | } 16 | 17 | /* 18 | func StructTypeCompare2() { 19 | type Student struct { 20 | name string 21 | grade map[string]int 22 | } 23 | 24 | zhangsan := Student{name: "Zhang San"} 25 | lisi := Student{name: "Li Si"} 26 | 27 | fmt.Println(zhangsan == lisi) // Invalid operation: the operator == is not defined on Student 28 | } 29 | */ 30 | 31 | type Animal interface { 32 | Speak() string 33 | } 34 | 35 | type Duck struct { 36 | Name string 37 | } 38 | 39 | func (a Duck) Speak() string { 40 | return "I'm " + a.Name 41 | } 42 | 43 | type Cat struct { 44 | Name string 45 | } 46 | 47 | func (a Cat) Speak() string { 48 | return "I'm " + a.Name 49 | } 50 | 51 | func InterfaceTypeCompare() { 52 | var d1, d2, c1 Animal 53 | d1 = Duck{Name: "Donald Duck"} 54 | d2 = Duck{Name: "Donald Duck"} 55 | fmt.Println(d1 == d2) // 输出 true 56 | 57 | c1 = Cat{Name: "Donald Duck"} // 伪装的 duck 58 | fmt.Println(d1 == c1) // 输出 false 59 | } 60 | 61 | func InterfaceAndStructCompare() { 62 | var animal Animal 63 | animal = Duck{Name: "Donald Duck"} 64 | var duck Duck 65 | duck = Duck{Name: "Donald Duck"} 66 | fmt.Println(animal == duck) // 输出 true 67 | } 68 | 69 | func ArrayCompare() { 70 | arr1 := [10]int{1, 2, 3} 71 | arr2 := [10]int{1, 2} 72 | 73 | fmt.Println(arr1 == arr2) // 输出 false 74 | arr2[2] = 3 75 | fmt.Println(arr1 == arr2) // 输出 true 76 | } 77 | 78 | func ComplexCompare() { 79 | c1 := complex(1, 2) 80 | c2 := complex(1, 2) 81 | c3 := complex(1, 3) 82 | 83 | fmt.Println(c1 == c2) // 输出 true 84 | fmt.Println(c1 == c3) // 输出 false 85 | } 86 | -------------------------------------------------------------------------------- /compare/compare_test.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | func ExampleStructTypeCompare() { 4 | StructTypeCompare() 5 | // Output: 6 | // false 7 | } 8 | 9 | func ExampleInterfaceTypeCompare() { 10 | InterfaceTypeCompare() 11 | // Output: 12 | // true 13 | // false 14 | } 15 | 16 | func ExampleInterfaceAndStructCompare() { 17 | InterfaceAndStructCompare() 18 | // Output: 19 | // true 20 | } 21 | 22 | func ExampleArrayCompare() { 23 | ArrayCompare() 24 | // Output: 25 | // false 26 | // true 27 | } 28 | 29 | func ExampleComplexCompare() { 30 | ComplexCompare() 31 | // Output: 32 | // true 33 | // false 34 | } 35 | -------------------------------------------------------------------------------- /compare/uncomparable.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | import "fmt" 4 | 5 | /* 6 | func SliceCompare() { 7 | s1 := make([]int, 3) 8 | s2 := make([]int, 3) 9 | fmt.Println(s1 == s2) // the operator == is not defined on []int 10 | } 11 | */ 12 | 13 | type Bird struct { 14 | Name string 15 | SpeakFunc func() string 16 | } 17 | 18 | func (a Bird) Speak() string { 19 | return "I'm " + a.SpeakFunc() 20 | } 21 | func UncomparablePanic() { 22 | defer func() { 23 | if err := recover(); err != nil { 24 | fmt.Println("panic") 25 | } 26 | }() 27 | 28 | var b1 Animal = Bird{ 29 | Name: "bird", 30 | SpeakFunc: func() string { 31 | return "I'm Poly" 32 | }} 33 | var b2 Animal = Bird{ 34 | Name: "bird", 35 | SpeakFunc: func() string { 36 | return "I'm eagle" 37 | }} 38 | 39 | fmt.Println(b1 == b2) // panic: comparing uncomparable type compare.Bird 40 | } 41 | -------------------------------------------------------------------------------- /compare/uncomparable_test.go: -------------------------------------------------------------------------------- 1 | package compare 2 | 3 | func ExampleUncomparablePanic() { 4 | UncomparablePanic() 5 | // Output: 6 | // panic 7 | } 8 | -------------------------------------------------------------------------------- /defer/deferexam.go: -------------------------------------------------------------------------------- 1 | package _defer 2 | 3 | import "fmt" 4 | 5 | func DeferDemo1() { 6 | for i := 0; i < 5; i++ { 7 | defer fmt.Print(i) 8 | } 9 | } 10 | 11 | func DeferDemo2() { 12 | var aInt = 1 13 | 14 | defer fmt.Println(aInt) 15 | 16 | aInt = 2 17 | return 18 | } 19 | 20 | func DeferDemo3() { 21 | var i = 0 22 | defer func() { 23 | fmt.Println(i) 24 | }() 25 | i++ 26 | } 27 | 28 | func DeferDemo4() { 29 | var aArray = [3]int{1, 2, 3} 30 | defer func(array *[3]int) { 31 | for i := range array { 32 | fmt.Print(array[i]) 33 | } 34 | }(&aArray) 35 | aArray[0] = 10 36 | } 37 | 38 | func DeferDemo5() (result int) { 39 | i := 1 40 | 41 | defer func() { 42 | result++ 43 | }() 44 | 45 | return i 46 | } 47 | 48 | func DeferDemo6() { 49 | defer func() { 50 | defer func() { 51 | fmt.Print("B") 52 | }() 53 | fmt.Print("A") 54 | }() 55 | } 56 | -------------------------------------------------------------------------------- /defer/deferexam_test.go: -------------------------------------------------------------------------------- 1 | package _defer 2 | 3 | import "fmt" 4 | 5 | // defer执行顺序后进先出 6 | func ExampleDeferOrder() { 7 | DeferDemo1() 8 | // Output: 9 | // 43210 10 | } 11 | 12 | func ExampleDeferPinVar() { 13 | DeferDemo2() 14 | // Output: 15 | // 1 16 | } 17 | 18 | func ExampleDeferPinFun() { 19 | DeferDemo3() 20 | // Output: 21 | // 1 22 | } 23 | 24 | func ExampleDeferPinAddr() { 25 | DeferDemo4() 26 | // Output: 27 | // 1023 28 | } 29 | 30 | func ExampleDeferReturn() { 31 | result := DeferDemo5() 32 | fmt.Print(result) 33 | // Output: 34 | // 2 35 | } 36 | 37 | func ExampleDeferNest() { 38 | DeferDemo6() 39 | // Output: 40 | // AB 41 | } 42 | -------------------------------------------------------------------------------- /errors/chanerror.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func AssertChanErrorWithoutAs(err error) { 10 | if e, ok := err.(*os.PathError); ok { 11 | fmt.Printf("it's an os.PathError, operation: %s, path: %s, msg: %v\n", e.Op, e.Path, e.Err) 12 | } 13 | } 14 | 15 | func AssertChanErrorWithAs(err error) { 16 | var e *os.PathError 17 | if errors.As(err, &e) { 18 | fmt.Printf("it's an os.PathError, operation: %s, path: %s, msg: %v\n", e.Op, e.Path, e.Err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /errors/chanerror_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func ExampleCreateBasicError() { 10 | err := errors.New("this is demo error") 11 | 12 | basicErr := fmt.Errorf("some context: %v", err) // 使用 %v 13 | if _, ok := basicErr.(interface{ Unwrap() error }); !ok { // 如果errBasic没有实现Unwrap接口 14 | fmt.Print("basicErr is a errorString") 15 | } 16 | // Output: 17 | // basicErr is a errorString 18 | } 19 | 20 | func ExampleCreateWrapError() { 21 | err := errors.New("this is demo error") 22 | 23 | wrapError := fmt.Errorf("some context: %w", err) // 使用%w 24 | if _, ok := wrapError.(interface{ Unwrap() error }); ok { // 如果wrapError实现了Unwrap接口 25 | fmt.Print("wrapError is a wrapError") 26 | } 27 | // Output: 28 | // wrapError is a wrapError 29 | } 30 | 31 | /* 32 | // 编译错误:Errorf call has more than one error-wrapping directive %w 33 | func ExampleTwoVerb() { 34 | err := errors.New("this is demo error") 35 | 36 | wrapError := fmt.Errorf("some context: %w, %w", err, err) 37 | fmt.Printf(wrapError.Error()) 38 | // Output: 39 | // 40 | } 41 | */ 42 | 43 | /* 44 | 编译错误: Errorf format %w has arg "some string" of wrong type string 45 | func ExampleNonError() { 46 | wrapError := fmt.Errorf("some context: %w", "some string") 47 | fmt.Printf(wrapError.Error()) 48 | // Output: 49 | // 50 | } 51 | */ 52 | 53 | func ExampleUnwrap() { 54 | err := fmt.Errorf("write file error: %w", os.ErrPermission) 55 | if errors.Unwrap(err) == os.ErrPermission { 56 | fmt.Printf("permission denied") 57 | } 58 | // Output: 59 | // permission denied 60 | } 61 | 62 | func ExampleUnwrapLoop() { 63 | err1 := fmt.Errorf("write file error: %w", os.ErrPermission) 64 | err2 := fmt.Errorf("write file error: %w", err1) 65 | 66 | err := err2 67 | for { 68 | if err == os.ErrPermission { 69 | fmt.Printf("permission denied") 70 | break 71 | } 72 | if err = errors.Unwrap(err); err == nil { 73 | break 74 | } 75 | } 76 | // Output: 77 | // permission denied 78 | } 79 | 80 | func ExampleIs() { 81 | err1 := fmt.Errorf("write file error: %w", os.ErrPermission) 82 | err2 := fmt.Errorf("write file error: %w", err1) 83 | 84 | if errors.Is(err2, os.ErrPermission) { 85 | fmt.Printf("permission denied") 86 | } 87 | // Output: 88 | // permission denied 89 | } 90 | 91 | func ExampleAssertChanErrorWithoutAs() { 92 | err := &os.PathError{ 93 | Op: "write", 94 | Path: "/root/demo.txt", 95 | Err: os.ErrPermission, 96 | } 97 | 98 | err2 := fmt.Errorf("some context: %w", err) 99 | if e, ok := err2.(*os.PathError); ok { // 判断失效 100 | fmt.Printf("it's an os.PathError, operation: %s, path: %s, msg: %v\n", e.Op, e.Path, e.Err) 101 | } 102 | // Output: 103 | // 104 | } 105 | 106 | func ExampleAssertChanWithAs() { 107 | err := &os.PathError{ 108 | Op: "write", 109 | Path: "/root/demo.txt", 110 | Err: os.ErrPermission, 111 | } 112 | 113 | err2 := fmt.Errorf("some context: %w", err) 114 | var target *os.PathError 115 | if errors.As(err2, &target) { // 逐层剥离err2并检测是否是os.PathError类型 116 | fmt.Printf("it's an os.PathError, operation: %s, path: %s, msg: %v\n", target.Op, target.Path, target.Err) 117 | } 118 | // Output: 119 | // it's an os.PathError, operation: write, path: /root/demo.txt, msg: permission denied 120 | } 121 | -------------------------------------------------------------------------------- /errors/errors.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | type NotFoundError struct { 10 | Name string 11 | } 12 | 13 | func (e *NotFoundError) Error() string { return e.Name + ": not found" } 14 | 15 | var _ error = &NotFoundError{} 16 | 17 | func NewNotFoundError(name string) error { 18 | return &NotFoundError{Name: name} 19 | } 20 | 21 | func MakeByErrorsNew() error { 22 | return errors.New("new error") 23 | } 24 | 25 | func MakeByFmtErrorf() error { 26 | return fmt.Errorf("new error") 27 | } 28 | 29 | func AssertError(err error) { 30 | if e, ok := err.(*os.PathError); ok { 31 | fmt.Printf("it's an os.PathError, operation: %s, path: %s, msg: %v\n", e.Op, e.Path, e.Err) 32 | } 33 | 34 | if e, ok := err.(*os.PathError); ok && e.Err == os.ErrPermission { 35 | fmt.Printf("permission denied\n") 36 | } 37 | } 38 | 39 | func WriteFile(fileName string) error { 40 | if fileName == "a.txt" { 41 | return fmt.Errorf("write file error: %v", os.ErrPermission) 42 | } 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /errors/errors_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | /* 11 | 官方博客中出现的一个笔误: 12 | 原文链接:https://blog.golang.org/go1.13-errors 13 | 原文如下: 14 | type NotFoundError struct { 15 | Name string 16 | } 17 | 18 | func (e *NotFoundError) Error() string { return e.Name + ": not found" } 19 | 20 | if e, ok := err.(*NotFoundError); ok { 21 | // e.Name wasn't found 22 | } 23 | 24 | 其中“e.Name wasn't found” 错误,实际应该是“e.Name was found” 25 | 26 | 修复该笔误的PR:https://github.com/golang/blog/pull/33 27 | 更新:是笔者理解错了,`e.Name wasn't found`并不是指err中没有e.Name成员(从而不是NotFoundError),而是指e.Name的值没有找到。 28 | */ 29 | 30 | func ExampleNotFoundError_Error() { 31 | err1 := errors.New("this is not NotFoundError") 32 | if e, ok := err1.(*NotFoundError); ok { 33 | fmt.Printf("err1 is a NotFoundError, e.Name=%s", e.Name) 34 | } 35 | 36 | err2 := NewNotFoundError("err2") 37 | 38 | if e, ok := err2.(*NotFoundError); ok { 39 | fmt.Printf("err2 is a NotFoundError, e.Name=%s", e.Name) 40 | } 41 | 42 | // OutPut: 43 | // err2 is a NotFoundError, e.Name=err2 44 | } 45 | 46 | // errors.New() 性能测试 47 | // [root@ecs-d8b6 errors]# benchstat new.txt 48 | // name time/op 49 | // MakeByErrorsNew-12 0.24ns ± 1% 50 | func BenchmarkMakeByErrorsNew(b *testing.B) { 51 | for i := 0; i < b.N; i++ { 52 | _ = MakeByErrorsNew() 53 | } 54 | } 55 | 56 | // fmt.Errorf() 性能测试 57 | // [root@ecs-d8b6 errors]# benchstat old.txt 58 | // name time/op 59 | // MakeByFmtErrorf-12 80.9ns ± 1% 60 | func BenchmarkMakeByFmtErrorf(b *testing.B) { 61 | for i := 0; i < b.N; i++ { 62 | _ = MakeByFmtErrorf() 63 | } 64 | } 65 | 66 | // go test ./errors -run=ExampleAssertError 67 | func ExampleAssertError() { 68 | err1 := &os.PathError{ 69 | Op: "write", 70 | Path: "/root/demo.txt", 71 | Err: os.ErrPermission, 72 | } 73 | AssertError(err1) 74 | 75 | err2 := fmt.Errorf("not an os.PathError") 76 | AssertError(err2) 77 | 78 | // Output: 79 | // it's an os.PathError, operation: write, path: /root/demo.txt, msg: permission denied 80 | // permission denied 81 | } 82 | 83 | // go test ./errors -run=ExampleWriteFile 84 | func ExampleWriteFile() { 85 | err := WriteFile("a.txt") 86 | if err == os.ErrPermission { 87 | fmt.Printf("permission denied") 88 | } 89 | // Output: 90 | // 91 | } 92 | -------------------------------------------------------------------------------- /errors/exam.go: -------------------------------------------------------------------------------- 1 | package errors 2 | -------------------------------------------------------------------------------- /errors/exam_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // 内容为空的error也是异常。 10 | func ExampleEmptyError() { 11 | err := errors.New("") 12 | if err != nil { 13 | fmt.Printf("empty error still is an error") 14 | } 15 | // OutPut: 16 | // empty error still is an error 17 | } 18 | 19 | func ExampleFormatVerb() { 20 | err := errors.New("not found") 21 | err1 := fmt.Errorf("some context: %v", err) 22 | err2 := fmt.Errorf("some context: %w", err) 23 | 24 | if err1 == err2 { 25 | fmt.Printf("two errors are equal\n") 26 | } else { 27 | fmt.Printf("two errors are different\n") 28 | } 29 | 30 | if err1.Error() != err2.Error() { 31 | panic("two errors's content should be same") 32 | } 33 | 34 | fmt.Printf("%s\n", reflect.TypeOf(err1).String()) 35 | fmt.Printf("%s\n", reflect.TypeOf(err2).String()) 36 | 37 | // Output: 38 | // two errors are different 39 | // *errors.errorString 40 | // *fmt.wrapError 41 | } 42 | 43 | func ExampleUnwrapBasicError() { 44 | err := errors.New("not found") 45 | 46 | err = errors.Unwrap(err) 47 | switch err { 48 | case nil: 49 | fmt.Printf("err is nil") 50 | default: 51 | fmt.Printf("err is non-nil") 52 | } 53 | 54 | // Output: 55 | // err is nil 56 | } 57 | -------------------------------------------------------------------------------- /generics/constraint/approximation.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | import "fmt" 4 | 5 | type MyString string 6 | 7 | // AnyString 定义了一个宽泛的类型集合,只要类型底层类型为string即可 8 | // 如果没有使用`~`,则即便底层类型为string,也会有编译错误: 9 | // Type does not implement constraint 'AnyString' because type is not included in type set ('string') 10 | type AnyString interface { 11 | ~string 12 | } 13 | 14 | func SayHi[T AnyString](name T) { 15 | fmt.Printf("Hi %s", name) 16 | } 17 | 18 | /* 19 | 不能使用interface表示底层类型 20 | type InterfaceIsNotAllowed interface { 21 | ~AnyString // 编译错误:Invalid use of ~ ('AnyString' is an interface) 22 | } 23 | */ 24 | 25 | /* 26 | 底层类型不是自己的,不能用于~之后 27 | type UnderlyingTypeNotMatched interface { 28 | ~MyString // Invalid use of ~ (underlying type of 'MyString' is not 'MyString') 29 | } 30 | */ 31 | -------------------------------------------------------------------------------- /generics/constraint/approximation_test.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | func ExampleSayHi() { 4 | var s MyString = "John" 5 | SayHi(s) 6 | // Output: 7 | // Hi John 8 | } 9 | -------------------------------------------------------------------------------- /generics/constraint/arbitrary.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | type Integer interface { 4 | int 5 | } 6 | 7 | type MyInteger interface { 8 | Integer 9 | } 10 | 11 | type MyType int 12 | 13 | type MyTypeIface interface { 14 | MyType 15 | } 16 | 17 | /* 18 | // 不能嵌入类型参数中的类型 19 | // Cannot embed a type parameter 20 | type EmbeddedParameter[T any] interface { 21 | T 22 | } 23 | */ 24 | -------------------------------------------------------------------------------- /generics/constraint/arbitrary_test.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | func SumInteger[T MyInteger](a T, b T) T { 4 | return a + b 5 | } 6 | -------------------------------------------------------------------------------- /generics/constraint/operationbased.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | // Ordered is a type constraint that matches any ordered type. 4 | // An ordered type is one that supports the <, <=, >, and >= operators. 5 | type Ordered interface { 6 | ~int | ~int8 | ~int16 | ~int32 | ~int64 | 7 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | 8 | ~float32 | ~float64 | 9 | ~string 10 | } 11 | 12 | func GreaterThan[T Ordered](a, b T) bool { 13 | if a > b { 14 | return true 15 | } 16 | 17 | return false 18 | } 19 | -------------------------------------------------------------------------------- /generics/constraint/operationbased_test.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | import "testing" 4 | 5 | func TestGreaterThan(t *testing.T) { 6 | var aInt, bInt = 1, 2 7 | if GreaterThan(aInt, bInt) { 8 | t.Fatalf("aInt(%d) should not greater than bInt(%d)", aInt, bInt) 9 | } 10 | 11 | var aStr, bStr = "aaa", "bbb" 12 | if GreaterThan(aStr, bStr) { 13 | t.Fatalf("aStr(%s) should not greater than bStr(%s)", aStr, bStr) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /generics/constraint/union.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | 3 | // PredeclaredSignedInteger is a constraint that matches the 4 | // five predeclared signed integer types. 5 | type PredeclaredSignedInteger interface { 6 | int | int8 | int16 | int32 | int64 7 | } 8 | 9 | // SignedInteger is a constraint that matches any signed integer type. 10 | type SignedInteger interface { 11 | ~int | ~int8 | ~int16 | ~int32 | ~int64 12 | } 13 | -------------------------------------------------------------------------------- /generics/constraint/union_test.go: -------------------------------------------------------------------------------- 1 | package constraint 2 | -------------------------------------------------------------------------------- /generics/examples/mapkeys.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | // MapKeys returns the keys of the map m in a slice. 4 | // The keys will be returned in an unpredictable order. 5 | // This function has two type parameters, K and V. 6 | // Map keys must be comparable, so key has the predeclared 7 | // constraint comparable. Map values can be any type. 8 | func MapKeys[K comparable, V any](m map[K]V) []K { 9 | r := make([]K, 0, len(m)) 10 | for k := range m { 11 | r = append(r, k) 12 | } 13 | return r 14 | } 15 | -------------------------------------------------------------------------------- /generics/examples/mapkeys_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "testing" 4 | 5 | func TestMapKeys(t *testing.T) { 6 | m := map[int]int{1: 2, 2: 4} 7 | k := MapKeys(m) 8 | if len(k) != 2 { 9 | t.Fatalf("Expect two eletems, bug got: %d", len(k)) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /generics/examples/sets.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "sync" 4 | 5 | // Set 底层使用map实现 6 | type Set[T comparable] map[T]struct{} 7 | 8 | // MakeSet 构造某个(comparable)类型的 set 9 | func MakeSet[T comparable]() Set[T] { 10 | return make(Set[T]) 11 | } 12 | 13 | // Add 添加元素v 14 | func (s Set[T]) Add(v T) { 15 | s[v] = struct{}{} 16 | } 17 | 18 | // Delete 删除元素v 19 | // 如果v不存在等同于空操作 20 | func (s Set[T]) Delete(v T) { 21 | delete(s, v) 22 | } 23 | 24 | // Contains 查询元素v是否已存在 25 | func (s Set[T]) Contains(v T) bool { 26 | _, ok := s[v] 27 | return ok 28 | } 29 | 30 | // Len 返回元素个数 31 | func (s Set[T]) Len() int { 32 | return len(s) 33 | } 34 | 35 | // Iterate 遍历set,并逐个调用函数 f 36 | func (s Set[T]) Iterate(f func(T)) { 37 | for v := range s { 38 | f(v) 39 | } 40 | } 41 | 42 | func SetExample() { 43 | s := MakeSet[int]() // 构建一个存储int的set 44 | s.Add(1) 45 | if s.Contains(2) { 46 | // do something 47 | } 48 | } 49 | 50 | // ThreadSafeSet 行为同Set一致,但它可以是线程安全的。 51 | type ThreadSafeSet[T comparable] struct { 52 | l sync.RWMutex 53 | m map[T]struct{} 54 | } 55 | -------------------------------------------------------------------------------- /generics/examples/sets_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSet(t *testing.T) { 8 | s := MakeSet[int]() 9 | 10 | tests := []struct { 11 | name string 12 | inputs []int 13 | outputs []int 14 | }{ 15 | { 16 | name: "thread1 to crud", 17 | inputs: []int{1, 2, 3}, 18 | outputs: []int{1, 2, 3}, 19 | }, 20 | { 21 | name: "thread2 to crud", 22 | inputs: []int{1, 2, 3}, 23 | outputs: []int{1, 2, 3}, 24 | }, 25 | } 26 | 27 | for _, test := range tests { 28 | tc := test 29 | t.Run(tc.name, func(t *testing.T) { 30 | t.Parallel() 31 | for i := range tc.inputs { 32 | s.Add(tc.inputs[i]) 33 | if !s.Contains(tc.inputs[i]) { 34 | t.Fatalf("unexpected") 35 | } 36 | } 37 | }) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /generics/examples/sort.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import "sort" 4 | 5 | // Ordered 定义适用于所有可排序类型的类型集合 6 | // 可排序类型是指支持 <、<=、>=、>操作的类型 7 | type Ordered interface { 8 | ~int | ~int8 | ~int16 | ~int32 | ~int64 | 9 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | 10 | ~float32 | ~float64 | 11 | ~string 12 | } 13 | 14 | // orderedSlice 实现了sort.Interface,所以可以使用sort.Sort排序 15 | type orderedSlice[T Ordered] []T 16 | 17 | func (s orderedSlice[T]) Len() int { return len(s) } 18 | func (s orderedSlice[T]) Less(i, j int) bool { return s[i] < s[j] } 19 | func (s orderedSlice[T]) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 20 | 21 | // OrderedSlice 按升序排列slice 22 | func OrderedSlice[T Ordered](s []T) { 23 | // s先被转换为orderedSlice,然后再排序 24 | // 因此s不必再实现sort.Interface接口 25 | sort.Sort(orderedSlice[T](s)) 26 | } 27 | -------------------------------------------------------------------------------- /generics/examples/sort_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "reflect" 5 | "sort" 6 | "testing" 7 | ) 8 | 9 | func TestPreviousUsage(t *testing.T) { 10 | s := []int{3, 5, 2} 11 | sort.Slice(s, func(i, j int) bool { 12 | if s[i] < s[j] { 13 | return true 14 | } 15 | return false 16 | }) 17 | 18 | if !reflect.DeepEqual([]int{2, 3, 5}, s) { 19 | t.Fatalf("unexpected, got: %v", s) 20 | } 21 | } 22 | 23 | func TestGenericUsage(t *testing.T) { 24 | s := []int{3, 5, 2} 25 | OrderedSlice(s) 26 | 27 | if !reflect.DeepEqual([]int{2, 3, 5}, s) { 28 | t.Fatalf("unexpected, got: %v", s) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /generics/overall/genericfunctions.go: -------------------------------------------------------------------------------- 1 | package overall 2 | 3 | // SumIntsOrFloats sums the values of map m. It supports both int64 and float64 4 | // as types for map values. 5 | func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { 6 | var s V 7 | for _, v := range m { 8 | s += v 9 | } 10 | return s 11 | } 12 | -------------------------------------------------------------------------------- /generics/overall/genericfunctions_test.go: -------------------------------------------------------------------------------- 1 | package overall 2 | 3 | import "testing" 4 | 5 | func TestSumIntsOrFloats_Explicitly(t *testing.T) { 6 | scores := map[string]int64{"Jim": 80, "John": 90} 7 | if SumIntsOrFloats[string, int64](scores) != 170 { 8 | t.Fatalf("expected: 170, but got: SumIntsOrFloats(scores)") 9 | } 10 | 11 | stocks := map[int]float64{600718: 10.92, 600519: 1516.57} 12 | if SumIntsOrFloats[int, float64](stocks) != (10.92 + 1516.57) { 13 | t.Fatalf("expected: %f, bug got: %f", 10.92+1516.57, SumIntsOrFloats(stocks)) 14 | } 15 | } 16 | 17 | func TestSumIntsOrFloats_Implicitly(t *testing.T) { 18 | scores := map[string]int64{"Jim": 80, "John": 90} 19 | if SumIntsOrFloats(scores) != 170 { 20 | t.Fatalf("expected: 170, but got: SumIntsOrFloats(scores)") 21 | } 22 | 23 | stocks := map[int]float64{600718: 10.92, 600519: 1516.57} 24 | if SumIntsOrFloats(stocks) != (10.92 + 1516.57) { 25 | t.Fatalf("expected: %f, bug got: %f", 10.92+1516.57, SumIntsOrFloats(stocks)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /generics/overall/generictypes.go: -------------------------------------------------------------------------------- 1 | package overall 2 | 3 | // Vector 是可容纳任意类型的容器 4 | type Vector[T any] []T 5 | 6 | // Push 加入元素到容器 7 | // 为泛型类型定义方法时,receiver类型必须带上类型参数 8 | func (v *Vector[T]) Push(x T) { 9 | *v = append(*v, x) 10 | } 11 | -------------------------------------------------------------------------------- /generics/overall/generictypes_test.go: -------------------------------------------------------------------------------- 1 | package overall 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestGenericTypesInstantiation(t *testing.T) { 9 | var intVec Vector[int] // 实例化为整型容器 10 | fmt.Print(intVec) // 为了消除"unused variable" 11 | var stringVec Vector[string] // 实例化为字符串容器 12 | fmt.Print(stringVec) // 为了消除"unused variable" 13 | } 14 | 15 | func ExampleVectorPush() { 16 | var v Vector[string] 17 | v.Push("Hello, World!") 18 | fmt.Print(v) 19 | // Output: 20 | // [Hello, World!] 21 | } 22 | -------------------------------------------------------------------------------- /generics/quickstart/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Number interface { 6 | int64 | float64 7 | } 8 | 9 | // SumInts adds together the values of m. 10 | func SumInts(m map[string]int64) int64 { 11 | var s int64 12 | for _, v := range m { 13 | s += v 14 | } 15 | return s 16 | } 17 | 18 | // SumFloats adds together the values of m. 19 | func SumFloats(m map[string]float64) float64 { 20 | var s float64 21 | for _, v := range m { 22 | s += v 23 | } 24 | return s 25 | } 26 | 27 | // SumIntsOrFloats sums the values of map m. It supports both int64 and float64 28 | // as types for map values. 29 | func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V { 30 | var s V 31 | for _, v := range m { 32 | s += v 33 | } 34 | return s 35 | } 36 | 37 | func main() { 38 | // Initialize a map for the integer values 39 | ints := map[string]int64{ 40 | "first": 34, 41 | "second": 12, 42 | } 43 | 44 | // Initialize a map for the float values 45 | floats := map[string]float64{ 46 | "first": 35.98, 47 | "second": 26.99, 48 | } 49 | 50 | fmt.Printf("Non-Generic Sums: %v and %v\n", 51 | SumInts(ints), 52 | SumFloats(floats)) 53 | 54 | fmt.Printf("Generic Sums: %v and %v\n", 55 | SumIntsOrFloats[string, int64](ints), 56 | SumIntsOrFloats[string, float64](floats)) 57 | 58 | fmt.Printf("Generic Sums, type parameters inferred: %v and %v\n", 59 | SumIntsOrFloats(ints), 60 | SumIntsOrFloats(floats)) 61 | } 62 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rainbowmango/goexpertprogrammingsourcecode 2 | 3 | go 1.18 4 | 5 | require github.com/golang/mock v1.4.4 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= 2 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 3 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 4 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 5 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 6 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 7 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 8 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 9 | -------------------------------------------------------------------------------- /gomock/mockreporter/mockreporter.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: gomock/reporter/reporter.go 3 | 4 | // Package mockreporter is a generated GoMock package. 5 | package mockreporter 6 | 7 | import ( 8 | gomock "github.com/golang/mock/gomock" 9 | reflect "reflect" 10 | ) 11 | 12 | // MockWeatherReporter is a mock of WeatherReporter interface 13 | type MockWeatherReporter struct { 14 | ctrl *gomock.Controller 15 | recorder *MockWeatherReporterMockRecorder 16 | } 17 | 18 | // MockWeatherReporterMockRecorder is the mock recorder for MockWeatherReporter 19 | type MockWeatherReporterMockRecorder struct { 20 | mock *MockWeatherReporter 21 | } 22 | 23 | // NewMockWeatherReporter creates a new mock instance 24 | func NewMockWeatherReporter(ctrl *gomock.Controller) *MockWeatherReporter { 25 | mock := &MockWeatherReporter{ctrl: ctrl} 26 | mock.recorder = &MockWeatherReporterMockRecorder{mock} 27 | return mock 28 | } 29 | 30 | // EXPECT returns an object that allows the caller to indicate expected use 31 | func (m *MockWeatherReporter) EXPECT() *MockWeatherReporterMockRecorder { 32 | return m.recorder 33 | } 34 | 35 | // Report mocks base method 36 | func (m *MockWeatherReporter) Report(city string) string { 37 | m.ctrl.T.Helper() 38 | ret := m.ctrl.Call(m, "Report", city) 39 | ret0, _ := ret[0].(string) 40 | return ret0 41 | } 42 | 43 | // Report indicates an expected call of Report 44 | func (mr *MockWeatherReporterMockRecorder) Report(city interface{}) *gomock.Call { 45 | mr.mock.ctrl.T.Helper() 46 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Report", reflect.TypeOf((*MockWeatherReporter)(nil).Report), city) 47 | } 48 | -------------------------------------------------------------------------------- /gomock/reporter/reporter.go: -------------------------------------------------------------------------------- 1 | package reporter 2 | 3 | // WeatherReporter 定义天气预报接口。 4 | // 实现者可以从任意渠道获取天气 5 | type WeatherReporter interface { 6 | // Report 报告某个城市的当天天气 7 | Report(city string) string 8 | } 9 | 10 | func SuitTravel(city string, reporter WeatherReporter) bool { 11 | weather := reporter.Report(city) 12 | if weather == "SUNNY" { // 天气晴朗,适宜出行 13 | return true 14 | } 15 | 16 | if weather == "TYPHOON" { // 台风不宜出行 17 | return false 18 | } 19 | 20 | return false // 天气不明,不宜出行 21 | } 22 | -------------------------------------------------------------------------------- /gomock/reporter/reporter_test.go: -------------------------------------------------------------------------------- 1 | package reporter 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/golang/mock/gomock" 7 | "github.com/rainbowmango/goexpertprogrammingsourcecode/gomock/mockreporter" 8 | ) 9 | 10 | func TestSuitTravel(t *testing.T) { 11 | ctl := gomock.NewController(t) 12 | defer ctl.Finish() 13 | 14 | fakeReporter := mockreporter.NewMockWeatherReporter(ctl) 15 | 16 | // 期望调用Report(),且参数为"beijing"时输出"SUNNY" 17 | fakeReporter.EXPECT().Report("beijing").Return("SUNNY") 18 | 19 | // 测试1:晴朗天气适合出行 20 | if SuitTravel("beijing", fakeReporter) != true { 21 | t.Errorf("expected true") 22 | } 23 | 24 | // 期望调用Report(),且参数为"shanghai"时输出"TYPHOON" 25 | fakeReporter.EXPECT().Report("shanghai").Return("TYPHOON") 26 | 27 | // 测试2:台风天气不适合出行 28 | if SuitTravel("shanghai", fakeReporter) != false { 29 | t.Errorf("expected false") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /gotest/fuzz/fuzz.go: -------------------------------------------------------------------------------- 1 | package fuzz 2 | 3 | import ( 4 | "errors" 5 | "unicode/utf8" 6 | ) 7 | 8 | func Reverse(s string) (string, error) { 9 | if !utf8.ValidString(s) { 10 | return s, errors.New("input is not valid UTF-8") 11 | } 12 | 13 | b := []byte(s) 14 | for i, j := 0, len(b)-1; i < len(b)/2; i, j = i+1, j-1 { 15 | b[i], b[j] = b[j], b[i] 16 | } 17 | return string(b), nil 18 | } 19 | 20 | func ReverseV2(s string) (string, error) { 21 | if !utf8.ValidString(s) { 22 | return s, errors.New("input is not valid UTF-8") 23 | } 24 | 25 | r := []rune(s) 26 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 27 | r[i], r[j] = r[j], r[i] 28 | } 29 | return string(r), nil 30 | } 31 | -------------------------------------------------------------------------------- /gotest/fuzz/fuzz_test.go: -------------------------------------------------------------------------------- 1 | package fuzz 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "unicode/utf8" 7 | ) 8 | 9 | func ExampleReverse() { 10 | input := "The quick brown fox jumped over the lazy dog" 11 | rev, _ := Reverse(input) 12 | doubleRev, _ := Reverse(rev) 13 | fmt.Printf("%s\n", doubleRev) 14 | // Output: 15 | // The quick brown fox jumped over the lazy dog 16 | } 17 | 18 | func TestReverse(t *testing.T) { 19 | testcases := []struct { 20 | in, want string 21 | }{ 22 | {in: "Hello, world", want: "dlrow ,olleH"}, 23 | {in: " ", want: " "}, 24 | {in: "!12345", want: "54321!"}, 25 | } 26 | for _, tc := range testcases { 27 | rev, err := Reverse(tc.in) 28 | if err != nil { 29 | t.Errorf("Unexpected error: %v", err) 30 | } 31 | if rev != tc.want { 32 | t.Errorf("Reverse: %q, want %q", rev, tc.want) 33 | } 34 | } 35 | } 36 | 37 | func FuzzReverse(f *testing.F) { 38 | testcases := []string{"Hello, world", " ", "!12345"} 39 | for _, tc := range testcases { 40 | f.Add(tc) // 输入测试种子 41 | } 42 | f.Fuzz(func(t *testing.T, orig string) { 43 | if !utf8.ValidString(orig) { // 忽略构造的无效字符(非UTF-8编码字符串) 44 | return 45 | } 46 | rev, err := Reverse(orig) 47 | if err != nil { 48 | t.Fatalf("unexpected error: %v", err) 49 | } 50 | 51 | if !utf8.ValidString(rev) { 52 | t.Fatalf("Reverse produced invalid UTF-8 string %q", rev) 53 | } 54 | 55 | doubleRev, err := Reverse(rev) 56 | if err != nil { 57 | t.Fatalf("unexpected error: %v", err) 58 | } 59 | 60 | if orig != doubleRev { 61 | t.Errorf("Before: %q, after: %q", orig, doubleRev) 62 | } 63 | }) 64 | } 65 | 66 | func TestReverseV2(t *testing.T) { 67 | testcases := []struct { 68 | in, want string 69 | }{ 70 | {in: "Hello, world", want: "dlrow ,olleH"}, 71 | {in: " ", want: " "}, 72 | {in: "!12345", want: "54321!"}, 73 | {in: "中国", want: "国中"}, 74 | } 75 | for _, tc := range testcases { 76 | rev, err := ReverseV2(tc.in) 77 | if err != nil { 78 | t.Errorf("Unexpected error: %v", err) 79 | } 80 | if rev != tc.want { 81 | t.Errorf("Reverse: %q, want %q", rev, tc.want) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /iota/exam.go: -------------------------------------------------------------------------------- 1 | package _iota 2 | 3 | import "fmt" 4 | 5 | func Exam1() { 6 | const ( 7 | mutexLocked = 1 << iota // mutex is locked 8 | mutexWoken 9 | mutexStarving 10 | mutexWaiterShift = iota 11 | starvationThresholdNs = 1e6 12 | ) 13 | 14 | fmt.Println(mutexLocked) 15 | fmt.Println(mutexWoken) 16 | fmt.Println(mutexStarving) 17 | fmt.Println(mutexWaiterShift) 18 | fmt.Println(starvationThresholdNs) 19 | } 20 | 21 | const ( 22 | // 常量的注释(文档) 23 | a, b = iota, iota // 常量的行注释 24 | ) 25 | -------------------------------------------------------------------------------- /iota/exam_test.go: -------------------------------------------------------------------------------- 1 | package _iota 2 | 3 | func ExampleExam1() { 4 | Exam1() 5 | // Output: 6 | // 1 7 | // 2 8 | // 4 9 | // 3 10 | // 1e+06 11 | } 12 | -------------------------------------------------------------------------------- /map/exam.go: -------------------------------------------------------------------------------- 1 | package _map 2 | 3 | /* 4 | 下面代码存在什么问题? 5 | */ 6 | var FruitColor map[string]string 7 | 8 | func AddFruit(name, color string) { 9 | FruitColor[name] = color 10 | } 11 | 12 | /* 13 | panic: assignment to entry in nil map 14 | */ 15 | 16 | var StudentScore map[string]int 17 | 18 | func GetScore(name string) int { 19 | score := StudentScore[name] 20 | return score 21 | } 22 | 23 | func GetScoreImproved(name string) int { 24 | score, ok := StudentScore[name] 25 | if ok { 26 | return score 27 | } 28 | 29 | return -1 30 | } 31 | -------------------------------------------------------------------------------- /map/exam_test.go: -------------------------------------------------------------------------------- 1 | package _map 2 | 3 | import "fmt" 4 | 5 | // panic: assignment to entry in nil map 6 | func ExampleAddFruit() { 7 | AddFruit("apple", "red") 8 | } 9 | 10 | func ExampleGetScore() { 11 | s := GetScore("Rainbow") 12 | fmt.Printf("score is %d\n", s) 13 | // Output: 14 | // score is 0 15 | } 16 | 17 | func ExampleGetScoreImproved() { 18 | s := GetScoreImproved("Rainbow") 19 | fmt.Printf("score is %d\n", s) 20 | // Output: 21 | // score is -1 22 | } 23 | -------------------------------------------------------------------------------- /map/map.go: -------------------------------------------------------------------------------- 1 | package _map 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // MapInitByLiteral 演示使用字面量初始化map 8 | func MapInitByLiteral() { 9 | m := map[string]int{ 10 | "apple": 2, 11 | "banana": 3, 12 | } 13 | 14 | for k, v := range m { 15 | fmt.Printf("%s-%d\n", k, v) 16 | } 17 | } 18 | 19 | // MapInitByMake 演示使用make初始化map 20 | func MapInitByMake() { 21 | m := make(map[string]int, 10) // 或 m := make(map[string]int) 22 | m["apple"] = 2 23 | m["banana"] = 3 24 | 25 | for k, v := range m { 26 | fmt.Printf("%s-%d\n", k, v) 27 | } 28 | } 29 | 30 | // 演示增删改查 31 | func MapCRUD() { 32 | m := make(map[string]string, 10) 33 | m["apple"] = "red" // 添加 34 | m["apple"] = "green" // 修改 35 | delete(m, "apple") // 删除 36 | v, exist := m["apple"] // 查询 37 | if exist { 38 | fmt.Printf("apple-%s\n", v) 39 | } 40 | } 41 | 42 | func EmptyMap() { 43 | var m1 map[string]int 44 | m2 := make(map[string]int) 45 | 46 | fmt.Printf("len(m1) = %d\n", len(m1)) // 0 47 | fmt.Printf("len(m2) = %d\n", len(m2)) // 0 48 | 49 | // nil map 可以查询 50 | v, exist := m1["apple"] 51 | if exist { 52 | fmt.Println(v) // 永不可达 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /map/map_test.go: -------------------------------------------------------------------------------- 1 | package _map 2 | 3 | func ExampleMapInitByLiteral() { 4 | MapInitByLiteral() 5 | // Unordered output: 6 | // apple-2 7 | // banana-3 8 | } 9 | 10 | func ExampleMapInitByMake() { 11 | MapInitByMake() 12 | // Unordered output: 13 | // apple-2 14 | // banana-3 15 | } 16 | 17 | func ExampleMapCRUD() { 18 | MapCRUD() 19 | // Output: 20 | // 21 | } 22 | 23 | func ExampleEmptyMap() { 24 | EmptyMap() 25 | // Output: 26 | // len(m1) = 0 27 | // len(m2) = 0 28 | } 29 | -------------------------------------------------------------------------------- /panic/exam.go: -------------------------------------------------------------------------------- 1 | package panic 2 | 3 | import "fmt" 4 | 5 | func foo() { 6 | defer fmt.Print("A") 7 | defer fmt.Print("B") 8 | 9 | fmt.Print("C") 10 | panic("demo") 11 | defer fmt.Print("D") 12 | } 13 | 14 | // 考查点:panic会触发单个函数中的所有defer函数 15 | func PanicDemo1() { 16 | defer func() { 17 | recover() 18 | }() 19 | 20 | foo() 21 | } 22 | 23 | // 考查点:panic会触发整个协程中的所有defer函数 24 | func PanicDemo2() { 25 | defer func() { 26 | recover() 27 | }() 28 | 29 | defer func() { 30 | fmt.Print("1") 31 | }() 32 | 33 | foo() 34 | } 35 | 36 | // 考察点: panic不会触发其他协程的defer函数 37 | func PanicDemo3() { 38 | defer func() { 39 | fmt.Print("demo") 40 | }() 41 | 42 | go foo() 43 | } 44 | 45 | func PanicDemo4() { 46 | defer func() { 47 | recover() 48 | }() 49 | 50 | defer fmt.Print("A") 51 | 52 | defer func() { 53 | fmt.Print("B") 54 | panic("panic in defer") 55 | fmt.Print("C") 56 | }() 57 | 58 | panic("panic") 59 | 60 | fmt.Print("D") 61 | } 62 | -------------------------------------------------------------------------------- /panic/exam_test.go: -------------------------------------------------------------------------------- 1 | package panic 2 | 3 | func ExamplePanicDemo1() { 4 | PanicDemo1() 5 | // Output: 6 | // CBA 7 | } 8 | 9 | func ExamplePanicDemo2() { 10 | PanicDemo2() 11 | // Output: 12 | // CBA1 13 | } 14 | 15 | // 会panic 16 | func ExamplePanicDemo3() { 17 | // PanicDemo3() 18 | } 19 | 20 | func ExamplePanicDemo4() { 21 | PanicDemo4() 22 | // Output: 23 | // BA 24 | } 25 | -------------------------------------------------------------------------------- /panic/panic.go: -------------------------------------------------------------------------------- 1 | package panic 2 | 3 | import "fmt" 4 | 5 | func FooPanicProcess() { 6 | ret := fooPanic() 7 | 8 | fmt.Printf("continue after a panic-recovered function.\n") 9 | fmt.Printf("the panic-recovered function return value is zero value. ret = %d\n", ret) 10 | } 11 | 12 | func fooPanic() int { 13 | defer func() { 14 | // rule: recover之后继续处理当前协程的defer 15 | fmt.Printf("after recover, continue call defer\n") 16 | }() 17 | defer func() { 18 | if msg := recover(); msg != nil { 19 | fmt.Printf("panic recovered: %v\n", msg) 20 | } 21 | }() 22 | 23 | panic("trigger panic") 24 | 25 | // rule: panic recover之后不会再返回panic点继续执行 26 | fmt.Printf("after recover, the process can not go back here anymore.") 27 | 28 | return 10 29 | } 30 | -------------------------------------------------------------------------------- /panic/panic_test.go: -------------------------------------------------------------------------------- 1 | package panic 2 | 3 | func ExampleFoo() { 4 | // FooPanicProcess() 5 | // Output: 6 | // 7 | } 8 | -------------------------------------------------------------------------------- /range/compile.go: -------------------------------------------------------------------------------- 1 | package _range 2 | 3 | func compile() { 4 | s := "hello" 5 | for range s { 6 | } 7 | } 8 | 9 | /* 10 | 从汇编码无法清晰地看出其实现原理 11 | E:\RainbowMango\GoExpertProgrammingSourceCode>go tool compile -S ./range/compile.go 12 | "".compile STEXT size=122 args=0x0 locals=0x30 13 | 0x0000 00000 (./range/compile.go:3) TEXT "".compile(SB), ABIInternal, $48-0 14 | 0x0000 00000 (./range/compile.go:3) MOVQ TLS, CX 15 | 0x0009 00009 (./range/compile.go:3) PCDATA $0, $-2 16 | 0x0009 00009 (./range/compile.go:3) MOVQ (CX)(TLS*2), CX 17 | 0x0010 00016 (./range/compile.go:3) PCDATA $0, $-1 18 | 0x0010 00016 (./range/compile.go:3) CMPQ SP, 16(CX) 19 | 0x0014 00020 (./range/compile.go:3) PCDATA $0, $-2 20 | 0x0014 00020 (./range/compile.go:3) JLS 115 21 | 0x0016 00022 (./range/compile.go:3) PCDATA $0, $-1 22 | 0x0016 00022 (./range/compile.go:3) SUBQ $48, SP 23 | 0x001a 00026 (./range/compile.go:3) MOVQ BP, 40(SP) 24 | 0x001f 00031 (./range/compile.go:3) LEAQ 40(SP), BP 25 | 0x0024 00036 (./range/compile.go:3) PCDATA $0, $-2 26 | 0x0024 00036 (./range/compile.go:3) PCDATA $1, $-2 27 | 0x0024 00036 (./range/compile.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 28 | 0x0024 00036 (./range/compile.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 29 | 0x0024 00036 (./range/compile.go:3) FUNCDATA $2, gclocals·568470801006e5c0dc3947ea998fe279(SB) 30 | 0x0024 00036 (./range/compile.go:3) PCDATA $0, $0 31 | 0x0024 00036 (./range/compile.go:3) PCDATA $1, $0 32 | 0x0024 00036 (./range/compile.go:3) XORL AX, AX 33 | 0x0026 00038 (./range/compile.go:5) CMPQ AX, $5 34 | 0x002a 00042 (./range/compile.go:5) JGE 105 35 | 0x002c 00044 (./range/compile.go:5) PCDATA $0, $1 36 | 0x002c 00044 (./range/compile.go:5) LEAQ go.string."hello"(SB), CX 37 | 0x0033 00051 (./range/compile.go:5) MOVBLZX (CX)(AX*1), DX 38 | 0x0037 00055 (./range/compile.go:5) CMPL DX, $128 39 | 0x003d 00061 (./range/compile.go:5) JGE 68 40 | 0x003f 00063 (./range/compile.go:5) PCDATA $0, $0 41 | 0x003f 00063 (./range/compile.go:5) INCQ AX 42 | 0x0042 00066 (./range/compile.go:5) JMP 38 43 | 0x0044 00068 (./range/compile.go:5) MOVQ CX, (SP) 44 | 0x0048 00072 (./range/compile.go:5) MOVQ $5, 8(SP) 45 | 0x0051 00081 (./range/compile.go:5) MOVQ AX, 16(SP) 46 | 0x0056 00086 (./range/compile.go:5) CALL runtime.decoderune(SB) 47 | 0x005b 00091 (./range/compile.go:5) MOVQ 32(SP), AX 48 | 0x0060 00096 (./range/compile.go:5) LEAQ go.string."hello"(SB), CX 49 | 0x0067 00103 (./range/compile.go:5) JMP 38 50 | 0x0069 00105 (./range/compile.go:5) PCDATA $0, $-1 51 | 0x0069 00105 (./range/compile.go:5) PCDATA $1, $-1 52 | 0x0069 00105 (./range/compile.go:5) MOVQ 40(SP), BP 53 | 0x006e 00110 (./range/compile.go:5) ADDQ $48, SP 54 | 0x0072 00114 (./range/compile.go:5) RET 55 | 0x0073 00115 (./range/compile.go:5) NOP 56 | 0x0073 00115 (./range/compile.go:3) PCDATA $1, $-1 57 | 0x0073 00115 (./range/compile.go:3) PCDATA $0, $-2 58 | 0x0073 00115 (./range/compile.go:3) CALL runtime.morestack_noctxt(SB) 59 | 0x0078 00120 (./range/compile.go:3) PCDATA $0, $-1 60 | 0x0078 00120 (./range/compile.go:3) JMP 0 61 | 0x0000 65 48 8b 0c 25 28 00 00 00 48 8b 89 00 00 00 00 eH..%(...H...... 62 | 0x0010 48 3b 61 10 76 5d 48 83 ec 30 48 89 6c 24 28 48 H;a.v]H..0H.l$(H 63 | 0x0020 8d 6c 24 28 31 c0 48 83 f8 05 7d 3d 48 8d 0d 00 .l$(1.H...}=H... 64 | 0x0030 00 00 00 0f b6 14 01 81 fa 80 00 00 00 7d 05 48 .............}.H 65 | 0x0040 ff c0 eb e2 48 89 0c 24 48 c7 44 24 08 05 00 00 ....H..$H.D$.... 66 | 0x0050 00 48 89 44 24 10 e8 00 00 00 00 48 8b 44 24 20 .H.D$......H.D$ 67 | 0x0060 48 8d 0d 00 00 00 00 eb bd 48 8b 6c 24 28 48 83 H........H.l$(H. 68 | 0x0070 c4 30 c3 e8 00 00 00 00 eb 86 .0........ 69 | rel 12+4 t=17 TLS+0 70 | rel 47+4 t=16 go.string."hello"+0 71 | rel 87+4 t=8 runtime.decoderune+0 72 | rel 99+4 t=16 go.string."hello"+0 73 | rel 116+4 t=8 runtime.morestack_noctxt+0 74 | go.cuinfo.packagename. SDWARFINFO dupok size=0 75 | 0x0000 5f 72 61 6e 67 65 _range 76 | go.string."hello" SRODATA dupok size=5 77 | 0x0000 68 65 6c 6c 6f hello 78 | go.loc."".compile SDWARFLOC size=0 79 | go.info."".compile SDWARFINFO size=45 80 | 0x0000 03 22 22 2e 63 6f 6d 70 69 6c 65 00 00 00 00 00 ."".compile..... 81 | 0x0010 00 00 00 00 00 00 00 00 00 00 00 00 01 9c 00 00 ................ 82 | 0x0020 00 00 01 0a 73 00 04 00 00 00 00 00 00 ....s........ 83 | rel 12+8 t=1 "".compile+0 84 | rel 20+8 t=1 "".compile+122 85 | rel 30+4 t=30 gofile..E:\RainbowMango\GoExpertProgrammingSourceCode\range\compile.go+0 86 | rel 39+4 t=29 go.info.string+0 87 | go.range."".compile SDWARFRANGE size=0 88 | go.debuglines."".compile SDWARFMISC size=21 89 | 0x0000 04 02 11 0a eb 06 9b 06 25 06 37 06 02 27 ff 71 ........%.7..'.q 90 | 0x0010 04 01 03 7e 01 ...~. 91 | gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8 92 | 0x0000 01 00 00 00 00 00 00 00 ........ 93 | gclocals·568470801006e5c0dc3947ea998fe279 SRODATA dupok size=10 94 | 0x0000 02 00 00 00 02 00 00 00 00 02 .......... 95 | 96 | */ 97 | -------------------------------------------------------------------------------- /range/exam.go: -------------------------------------------------------------------------------- 1 | package _range 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // 题目一:性能考察 10 | func FindMonkey(s []string) bool { 11 | for _, v := range s { 12 | if v == "monkey" { 13 | return true 14 | } 15 | } 16 | 17 | return false 18 | } 19 | 20 | func FindMonkeyImproved(s []string) bool { 21 | for i := range s { 22 | if s[i] == "monkey" { 23 | return true 24 | } 25 | } 26 | 27 | return false 28 | } 29 | 30 | // 题目二: 引用循环变量下标 31 | func PrintSlice() { 32 | s := []int{1, 2, 3} 33 | var wg sync.WaitGroup 34 | 35 | wg.Add(len(s)) 36 | for _, v := range s { 37 | go func() { 38 | fmt.Println(v) 39 | wg.Done() 40 | }() 41 | } 42 | wg.Wait() 43 | } 44 | 45 | // 题目三:range nil channel 永久阻塞 46 | func RangeNilChannel() { 47 | var c chan string 48 | 49 | for v := range c { 50 | fmt.Println(v) 51 | } 52 | } 53 | 54 | /* 55 | - A: 函数没有打印,正常退出 56 | - B: 遍历nil切片,函数会panic 57 | - C: 函数打印nil,然后退出 58 | - D: 函数没有打印,永远阻塞 59 | */ 60 | 61 | // 题目四: range 会一直阻塞到channel关闭 62 | func RangeTimer() { 63 | t := time.NewTimer(time.Second) 64 | 65 | for _ = range t.C { 66 | fmt.Println("hi") 67 | } 68 | } 69 | 70 | /* 71 | - A: 函数没有打印,直接退出 72 | - B: 函数打印"hi"后退出 73 | - C: 函数打印"hi"后阻塞 74 | - D: 函数panic 75 | */ 76 | 77 | // 题目五:动态遍历 78 | func RangeDemo() { 79 | s := []int{1, 2, 3} 80 | for i := range s { 81 | s = append(s, i) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /range/exam_test.go: -------------------------------------------------------------------------------- 1 | package _range 2 | 3 | import "testing" 4 | 5 | func BenchmarkFindMonkey(b *testing.B) { 6 | s := []string{"apple", "peach", "lion", "elephant", "monkey"} 7 | 8 | for i := 0; i < b.N; i++ { 9 | FindMonkey(s) 10 | } 11 | } 12 | 13 | func BenchmarkFindMonkeyImproved(b *testing.B) { 14 | s := []string{"apple", "peach", "lion", "elephant", "monkey"} 15 | 16 | for i := 0; i < b.N; i++ { 17 | FindMonkeyImproved(s) 18 | } 19 | } 20 | 21 | func ExamplePrintSlice() { 22 | PrintSlice() 23 | // Output: 24 | // 3 25 | // 3 26 | // 3 27 | } 28 | 29 | func ExampleRangeTimer() { 30 | // RangeTimer() // 会阻塞到go test 超时 31 | // Output: 32 | } 33 | 34 | func ExampleRangeDemo() { 35 | RangeDemo() 36 | // Output: 37 | } 38 | -------------------------------------------------------------------------------- /range/range.go: -------------------------------------------------------------------------------- 1 | package _range 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func ForExpression() { 9 | s := []int{1, 2, 3} 10 | 11 | for i := 0; i < len(s); i++ { 12 | fmt.Println(s[i]) 13 | } 14 | } 15 | 16 | func ForRangeExpression() { 17 | s := []int{1, 2, 3} 18 | 19 | for i := range s { 20 | fmt.Println(s[i]) 21 | } 22 | } 23 | 24 | // RangeArray 演示Range遍历数组 25 | func RangeArray() { 26 | a := [3]int{1, 2, 3} 27 | for i, v := range a { 28 | fmt.Printf("index: %d value:%d\n", i, v) 29 | } 30 | } 31 | 32 | // RangeArrayPointer 演示range遍历数组的指针 33 | // 数组的指针与数组一致 34 | func RangeArrayPointer() { 35 | a := [3]int{1, 2, 3} 36 | for i, v := range &a { 37 | fmt.Printf("index: %d value:%d\n", i, v) 38 | } 39 | } 40 | 41 | // Range遍历切片与遍历数组操作一致。 42 | // 但不能作用于切片的地址,否则会有编译错误: 43 | // cannot range over &s (type *[]int) 44 | func RangeSlice() { 45 | s := []int{1, 2, 3} 46 | for i, v := range s { 47 | fmt.Printf("index: %d value:%d\n", i, v) 48 | } 49 | } 50 | 51 | func RangeString() { 52 | s := "Hello" 53 | for i, v := range s { 54 | fmt.Printf("index: %d, value: %c\n", i, v) 55 | } 56 | } 57 | 58 | // len(“中国”) == 6,长度代表底层存储 59 | func RangeStringUniCode() { 60 | s := "中国" 61 | for i, v := range s { 62 | fmt.Printf("index: %d, value: %c\n", i, v) 63 | } 64 | } 65 | 66 | func RangeMap() { 67 | m := map[string]string{"animal": "monkey", "fruit": "apple"} 68 | for k, v := range m { 69 | fmt.Printf("key: %s, value: %s\n", k, v) 70 | } 71 | } 72 | 73 | func RangeChannel() { 74 | c := make(chan string, 2) 75 | c <- "Hello" 76 | c <- "World" 77 | 78 | time.AfterFunc(time.Microsecond, func() { 79 | close(c) 80 | }) 81 | 82 | for e := range c { 83 | fmt.Printf("element: %s\n", e) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /range/range_test.go: -------------------------------------------------------------------------------- 1 | package _range 2 | 3 | func ExampleRangeArray() { 4 | RangeArray() 5 | // Output: 6 | // index: 0 value:1 7 | // index: 1 value:2 8 | // index: 2 value:3 9 | } 10 | 11 | func ExampleRangeArrayPointer() { 12 | RangeArrayPointer() 13 | // Output: 14 | // index: 0 value:1 15 | // index: 1 value:2 16 | // index: 2 value:3 17 | } 18 | 19 | func ExampleRangeSlice() { 20 | RangeSlice() 21 | // Output: 22 | // index: 0 value:1 23 | // index: 1 value:2 24 | // index: 2 value:3 25 | } 26 | 27 | // TODO(RainbowMango): 如果字符串中包含空格,那么Example测试将失败,怀疑是Bug 28 | func ExampleRangeString() { 29 | RangeString() 30 | // Output: 31 | // index: 0, value: H 32 | // index: 1, value: e 33 | // index: 2, value: l 34 | // index: 3, value: l 35 | // index: 4, value: o 36 | } 37 | 38 | func ExampleRangeStringUniCode() { 39 | RangeStringUniCode() 40 | // Output: 41 | // index: 0, value: 中 42 | // index: 3, value: 国 43 | } 44 | 45 | func ExampleRangeMap() { 46 | RangeMap() 47 | // Unordered output: 48 | // key: animal, value: monkey 49 | // key: fruit, value: apple 50 | } 51 | 52 | func ExampleRangeChannel() { 53 | RangeChannel() 54 | // Output: 55 | // element: Hello 56 | // element: World 57 | 58 | } 59 | -------------------------------------------------------------------------------- /recover/compile.go: -------------------------------------------------------------------------------- 1 | package recover 2 | 3 | func compile() { 4 | defer func() { 5 | recover() 6 | }() 7 | } 8 | 9 | /* 10 | E:\RainbowMango\GoExpertProgrammingSourceCode>go tool compile -S recover/compile.go 11 | "".compile STEXT size=107 args=0x0 locals=0x18 12 | 0x0000 00000 (recover/compile.go:3) TEXT "".compile(SB), ABIInternal, $24-0 13 | 0x0000 00000 (recover/compile.go:3) MOVQ TLS, CX 14 | 0x0009 00009 (recover/compile.go:3) PCDATA $0, $-2 15 | 0x0009 00009 (recover/compile.go:3) MOVQ (CX)(TLS*2), CX 16 | 0x0010 00016 (recover/compile.go:3) PCDATA $0, $-1 17 | 0x0010 00016 (recover/compile.go:3) CMPQ SP, 16(CX) 18 | 0x0014 00020 (recover/compile.go:3) PCDATA $0, $-2 19 | 0x0014 00020 (recover/compile.go:3) JLS 100 20 | 0x0016 00022 (recover/compile.go:3) PCDATA $0, $-1 21 | 0x0016 00022 (recover/compile.go:3) SUBQ $24, SP 22 | 0x001a 00026 (recover/compile.go:3) MOVQ BP, 16(SP) 23 | 0x001f 00031 (recover/compile.go:3) LEAQ 16(SP), BP 24 | 0x0024 00036 (recover/compile.go:3) MOVQ $0, AX 25 | 0x002b 00043 (recover/compile.go:3) MOVQ AX, 8(SP) 26 | 0x0030 00048 (recover/compile.go:3) PCDATA $0, $-2 27 | 0x0030 00048 (recover/compile.go:3) PCDATA $1, $-2 28 | 0x0030 00048 (recover/compile.go:3) FUNCDATA $0, gclocals·69c1753bd5f81501d95132d08af04464(SB) 29 | 0x0030 00048 (recover/compile.go:3) FUNCDATA $1, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB) 30 | 0x0030 00048 (recover/compile.go:3) FUNCDATA $2, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB) 31 | 0x0030 00048 (recover/compile.go:3) FUNCDATA $5, "".compile.opendefer(SB) 32 | 0x0030 00048 (recover/compile.go:3) PCDATA $0, $0 33 | 0x0030 00048 (recover/compile.go:3) PCDATA $1, $0 34 | 0x0030 00048 (recover/compile.go:3) MOVB $0, ""..autotmp_1+7(SP) 35 | 0x0035 00053 (recover/compile.go:4) PCDATA $0, $1 36 | 0x0035 00053 (recover/compile.go:4) LEAQ "".compile.func1·f(SB), AX 37 | 0x003c 00060 (recover/compile.go:4) PCDATA $0, $0 38 | 0x003c 00060 (recover/compile.go:4) PCDATA $1, $1 39 | 0x003c 00060 (recover/compile.go:4) MOVQ AX, ""..autotmp_2+8(SP) 40 | 0x0041 00065 (recover/compile.go:7) MOVB $0, ""..autotmp_1+7(SP) 41 | 0x0046 00070 (recover/compile.go:7) CALL "".compile.func1(SB) 42 | 0x004b 00075 (recover/compile.go:7) MOVQ 16(SP), BP 43 | 0x0050 00080 (recover/compile.go:7) ADDQ $24, SP 44 | 0x0054 00084 (recover/compile.go:7) RET 45 | 0x0055 00085 (recover/compile.go:7) CALL runtime.deferreturn(SB) 46 | 0x005a 00090 (recover/compile.go:7) MOVQ 16(SP), BP 47 | 0x005f 00095 (recover/compile.go:7) ADDQ $24, SP 48 | 0x0063 00099 (recover/compile.go:7) RET 49 | 0x0064 00100 (recover/compile.go:7) NOP 50 | 0x0064 00100 (recover/compile.go:3) PCDATA $1, $-1 51 | 0x0064 00100 (recover/compile.go:3) PCDATA $0, $-2 52 | 0x0064 00100 (recover/compile.go:3) CALL runtime.morestack_noctxt(SB) 53 | 0x0069 00105 (recover/compile.go:3) PCDATA $0, $-1 54 | 0x0069 00105 (recover/compile.go:3) JMP 0 55 | 0x0000 65 48 8b 0c 25 28 00 00 00 48 8b 89 00 00 00 00 eH..%(...H...... 56 | 0x0010 48 3b 61 10 76 4e 48 83 ec 18 48 89 6c 24 10 48 H;a.vNH...H.l$.H 57 | 0x0020 8d 6c 24 10 48 c7 c0 00 00 00 00 48 89 44 24 08 .l$.H......H.D$. 58 | 0x0030 c6 44 24 07 00 48 8d 05 00 00 00 00 48 89 44 24 .D$..H......H.D$ 59 | 0x0040 08 c6 44 24 07 00 e8 00 00 00 00 48 8b 6c 24 10 ..D$.......H.l$. 60 | 0x0050 48 83 c4 18 c3 e8 00 00 00 00 48 8b 6c 24 10 48 H.........H.l$.H 61 | 0x0060 83 c4 18 c3 e8 00 00 00 00 eb 95 ........... 62 | rel 12+4 t=17 TLS+0 63 | rel 56+4 t=16 "".compile.func1·f+0 64 | rel 71+4 t=8 "".compile.func1+0 65 | rel 86+4 t=8 runtime.deferreturn+0 66 | rel 101+4 t=8 runtime.morestack_noctxt+0 67 | "".compile.func1 STEXT size=67 args=0x0 locals=0x20 68 | 0x0000 00000 (recover/compile.go:4) TEXT "".compile.func1(SB), ABIInternal, $32-0 69 | 0x0000 00000 (recover/compile.go:4) MOVQ TLS, CX 70 | 0x0009 00009 (recover/compile.go:4) PCDATA $0, $-2 71 | 0x0009 00009 (recover/compile.go:4) MOVQ (CX)(TLS*2), CX 72 | 0x0010 00016 (recover/compile.go:4) PCDATA $0, $-1 73 | 0x0010 00016 (recover/compile.go:4) CMPQ SP, 16(CX) 74 | 0x0014 00020 (recover/compile.go:4) PCDATA $0, $-2 75 | 0x0014 00020 (recover/compile.go:4) JLS 60 76 | 0x0016 00022 (recover/compile.go:4) PCDATA $0, $-1 77 | 0x0016 00022 (recover/compile.go:4) SUBQ $32, SP 78 | 0x001a 00026 (recover/compile.go:4) MOVQ BP, 24(SP) 79 | 0x001f 00031 (recover/compile.go:4) LEAQ 24(SP), BP 80 | 0x0024 00036 (recover/compile.go:4) PCDATA $0, $-2 81 | 0x0024 00036 (recover/compile.go:4) PCDATA $1, $-2 82 | 0x0024 00036 (recover/compile.go:4) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 83 | 0x0024 00036 (recover/compile.go:4) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 84 | 0x0024 00036 (recover/compile.go:4) FUNCDATA $2, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB) 85 | 0x0024 00036 (recover/compile.go:5) PCDATA $0, $1 86 | 0x0024 00036 (recover/compile.go:5) PCDATA $1, $0 87 | 0x0024 00036 (recover/compile.go:5) LEAQ ""..fp+40(SP), AX 88 | 0x0029 00041 (recover/compile.go:5) PCDATA $0, $0 89 | 0x0029 00041 (recover/compile.go:5) MOVQ AX, (SP) 90 | 0x002d 00045 (recover/compile.go:5) CALL runtime.gorecover(SB) 91 | 0x0032 00050 (recover/compile.go:6) MOVQ 24(SP), BP 92 | 0x0037 00055 (recover/compile.go:6) ADDQ $32, SP 93 | 0x003b 00059 (recover/compile.go:6) RET 94 | 0x003c 00060 (recover/compile.go:6) NOP 95 | 0x003c 00060 (recover/compile.go:4) PCDATA $1, $-1 96 | 0x003c 00060 (recover/compile.go:4) PCDATA $0, $-2 97 | 0x003c 00060 (recover/compile.go:4) CALL runtime.morestack_noctxt(SB) 98 | 0x0041 00065 (recover/compile.go:4) PCDATA $0, $-1 99 | 0x0041 00065 (recover/compile.go:4) JMP 0 100 | 0x0000 65 48 8b 0c 25 28 00 00 00 48 8b 89 00 00 00 00 eH..%(...H...... 101 | 0x0010 48 3b 61 10 76 26 48 83 ec 20 48 89 6c 24 18 48 H;a.v&H.. H.l$.H 102 | 0x0020 8d 6c 24 18 48 8d 44 24 28 48 89 04 24 e8 00 00 .l$.H.D$(H..$... 103 | 0x0030 00 00 48 8b 6c 24 18 48 83 c4 20 c3 e8 00 00 00 ..H.l$.H.. ..... 104 | 0x0040 00 eb bd ... 105 | rel 12+4 t=17 TLS+0 106 | rel 46+4 t=8 runtime.gorecover+0 107 | rel 61+4 t=8 runtime.morestack_noctxt+0 108 | go.cuinfo.packagename. SDWARFINFO dupok size=0 109 | 0x0000 72 65 63 6f 76 65 72 recover 110 | go.loc."".compile SDWARFLOC size=0 111 | go.info."".compile SDWARFINFO size=36 112 | 0x0000 03 22 22 2e 63 6f 6d 70 69 6c 65 00 00 00 00 00 ."".compile..... 113 | 0x0010 00 00 00 00 00 00 00 00 00 00 00 00 01 9c 00 00 ................ 114 | 0x0020 00 00 01 00 .... 115 | rel 0+0 t=24 type.func()+0 116 | rel 0+0 t=24 type.uint8+0 117 | rel 12+8 t=1 "".compile+0 118 | rel 20+8 t=1 "".compile+107 119 | rel 30+4 t=30 gofile..E:\RainbowMango\GoExpertProgrammingSourceCode\recover\compile.go+0 120 | go.range."".compile SDWARFRANGE size=0 121 | go.debuglines."".compile SDWARFMISC size=22 122 | 0x0000 04 02 11 0a eb 08 56 06 55 06 44 06 41 06 41 08 ......V.U.D.A.A. 123 | 0x0010 15 04 01 03 7e 01 ....~. 124 | go.loc."".compile.func1 SDWARFLOC size=0 125 | go.info."".compile.func1 SDWARFINFO size=42 126 | 0x0000 03 22 22 2e 63 6f 6d 70 69 6c 65 2e 66 75 6e 63 ."".compile.func 127 | 0x0010 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1............... 128 | 0x0020 00 00 01 9c 00 00 00 00 01 00 .......... 129 | rel 18+8 t=1 "".compile.func1+0 130 | rel 26+8 t=1 "".compile.func1+67 131 | rel 36+4 t=30 gofile..E:\RainbowMango\GoExpertProgrammingSourceCode\recover\compile.go+0 132 | go.range."".compile.func1 SDWARFRANGE size=0 133 | go.debuglines."".compile.func1 SDWARFMISC size=16 134 | 0x0000 04 02 12 0a eb 9c 06 41 06 6a 71 04 01 03 7d 01 .......A.jq...}. 135 | "".compile.func1·f SRODATA dupok size=8 136 | 0x0000 00 00 00 00 00 00 00 00 ........ 137 | rel 0+8 t=1 "".compile.func1+0 138 | runtime.memequal64·f SRODATA dupok size=8 139 | 0x0000 00 00 00 00 00 00 00 00 ........ 140 | rel 0+8 t=1 runtime.memequal64+0 141 | runtime.gcbits.01 SRODATA dupok size=1 142 | 0x0000 01 . 143 | type..namedata.*func()- SRODATA dupok size=10 144 | 0x0000 00 00 07 2a 66 75 6e 63 28 29 ...*func() 145 | type.*func() SRODATA dupok size=56 146 | 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................ 147 | 0x0010 9b 90 75 1b 08 08 08 36 00 00 00 00 00 00 00 00 ..u....6........ 148 | 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 149 | 0x0030 00 00 00 00 00 00 00 00 ........ 150 | rel 24+8 t=1 runtime.memequal64·f+0 151 | rel 32+8 t=1 runtime.gcbits.01+0 152 | rel 40+4 t=5 type..namedata.*func()-+0 153 | rel 48+8 t=1 type.func()+0 154 | type.func() SRODATA dupok size=56 155 | 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................ 156 | 0x0010 f6 bc 82 f6 02 08 08 33 00 00 00 00 00 00 00 00 .......3........ 157 | 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 158 | 0x0030 00 00 00 00 .... 159 | rel 32+8 t=1 runtime.gcbits.01+0 160 | rel 40+4 t=5 type..namedata.*func()-+0 161 | rel 44+4 t=6 type.*func()+0 162 | gclocals·69c1753bd5f81501d95132d08af04464 SRODATA dupok size=8 163 | 0x0000 02 00 00 00 00 00 00 00 ........ 164 | gclocals·9fb7f0986f647f17cb53dda1484e0f7a SRODATA dupok size=10 165 | 0x0000 02 00 00 00 01 00 00 00 00 01 .......... 166 | "".compile.opendefer SRODATA dupok size=6 167 | 0x0000 00 09 01 00 08 00 ...... 168 | gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8 169 | 0x0000 01 00 00 00 00 00 00 00 ........ 170 | 171 | */ 172 | -------------------------------------------------------------------------------- /recover/exam.go: -------------------------------------------------------------------------------- 1 | package recover 2 | 3 | import "fmt" 4 | 5 | // 考察点:recover之后,流程不会回到panic后面继续执行 6 | func RecoverDemo1() { 7 | defer func() { 8 | if err := recover(); err != nil { 9 | fmt.Println("A") 10 | } 11 | }() 12 | 13 | panic("demo") 14 | fmt.Println("B") 15 | } 16 | 17 | // 考察点:剩余defer中仍可以执行 18 | func RecoverDemo2() { 19 | defer func() { 20 | fmt.Println("C") 21 | }() 22 | defer func() { 23 | if err := recover(); err != nil { 24 | fmt.Println("A") 25 | } 26 | }() 27 | 28 | panic("demo") 29 | fmt.Println("B") 30 | } 31 | 32 | // 考察点:非顶层函数无法处理defer 33 | func RecoverDemo3() { 34 | defer func() { 35 | func() { 36 | if err := recover(); err != nil { 37 | fmt.Println("A") 38 | } 39 | }() 40 | }() 41 | 42 | panic("demo") 43 | fmt.Println("B") 44 | } 45 | 46 | // 考察点:两次recover 第二次无效 47 | func RecoverDemo4() { 48 | defer func() { 49 | if err := recover(); err != nil { 50 | fmt.Println("A") 51 | } 52 | }() 53 | 54 | defer func() { 55 | if err := recover(); err != nil { 56 | fmt.Println("B") 57 | } 58 | }() 59 | 60 | panic("demo") 61 | fmt.Println("C") 62 | } 63 | 64 | // 考察点:函数返回零值,且感知不到panic 65 | func RecoverDemo5() { 66 | foo := func() int { 67 | defer func() { 68 | recover() 69 | }() 70 | 71 | panic("demo") 72 | 73 | return 10 74 | } 75 | 76 | ret := foo() 77 | fmt.Println(ret) 78 | } 79 | 80 | // 考察点:panic(nil)时,recover()返回nil 81 | func RecoverDemo6() { 82 | defer func() { 83 | if err := recover(); err != nil { 84 | fmt.Println("A") 85 | } 86 | }() 87 | 88 | panic(nil) 89 | fmt.Println("B") 90 | } 91 | -------------------------------------------------------------------------------- /recover/exam_test.go: -------------------------------------------------------------------------------- 1 | package recover 2 | 3 | func ExampleRecoverDemo1() { 4 | RecoverDemo1() 5 | // Output: 6 | // A 7 | } 8 | 9 | func ExampleRecoverDemo2() { 10 | RecoverDemo2() 11 | // Output: 12 | // A 13 | // C 14 | } 15 | 16 | func ExampleRecoverDemo3() { 17 | defer func() { 18 | recover() 19 | }() 20 | RecoverDemo3() 21 | // Output: 22 | // 23 | } 24 | 25 | func ExampleRecoverDemo4() { 26 | RecoverDemo4() 27 | // Output: 28 | // B 29 | } 30 | 31 | func ExampleRecoverDemo5() { 32 | RecoverDemo5() 33 | // Output: 34 | // 0 35 | } 36 | 37 | func ExampleRecoverDemo6() { 38 | RecoverDemo6() 39 | // Output: 40 | // 41 | } 42 | -------------------------------------------------------------------------------- /recover/recover.go: -------------------------------------------------------------------------------- 1 | package recover 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | // 测试recover能否在具名函数中使用 9 | func ForRecover() { 10 | if p := recover(); p != nil { 11 | fmt.Printf("catch a recover from named-defer-function\n") 12 | } 13 | } 14 | 15 | func NamedRecover() { 16 | defer ForRecover() 17 | 18 | panic("this is a panic") 19 | } 20 | 21 | // 测试runtime.Goexit()会不会触发 defer 22 | func GoExit() { 23 | defer func() { 24 | fmt.Printf("runtime.Goexit will call defer like panic.\n") 25 | }() 26 | runtime.Goexit() 27 | } 28 | 29 | func GoExitRecover() { 30 | defer func() { 31 | if err := recover(); err == nil { 32 | fmt.Printf("runtime.Goexit() can not be recovered.\n") 33 | } 34 | }() 35 | runtime.Goexit() 36 | } 37 | -------------------------------------------------------------------------------- /recover/recover_test.go: -------------------------------------------------------------------------------- 1 | package recover 2 | 3 | import "fmt" 4 | 5 | func ExampleNamedRecover() { 6 | NamedRecover() 7 | // Output: 8 | // catch a recover from named-defer-function 9 | } 10 | 11 | func ExampleGoExit() { 12 | // GoExit() // go test ./recover 执行时会让hang住,暂不确定是否Go bug. 13 | // Output: 14 | // runtime.Goexit will call defer like panic. 15 | } 16 | 17 | func ExampleGoExitRecover() { 18 | fmt.Printf("program will hanging there!") 19 | // GoExitRecover() // go test ./recover 执行时会让hang住,暂不确定是否Go bug. 20 | // Output: 21 | // 22 | } 23 | -------------------------------------------------------------------------------- /reflection/interface.go: -------------------------------------------------------------------------------- 1 | package reflection 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func Law2() { 9 | var A interface{} 10 | A = 100 11 | 12 | v := reflect.ValueOf(A) 13 | B := v.Interface() 14 | 15 | if A == B { 16 | fmt.Printf("They are same!\n") 17 | } 18 | } 19 | 20 | func Law3Fail() { 21 | var x float64 = 3.4 22 | v := reflect.ValueOf(&x) 23 | v.SetFloat(7.1) // Error: will panic. 24 | fmt.Printf("x = %f\n", x) 25 | } 26 | -------------------------------------------------------------------------------- /reflection/interface_test.go: -------------------------------------------------------------------------------- 1 | package reflection 2 | 3 | func ExampleLaw2() { 4 | Law2() 5 | // Output: 6 | // They are same! 7 | } 8 | 9 | func ExampleLaw3Fail() { 10 | // Law3Fail() // panic: reflect: reflect.flag.mustBeAssignable using unaddressable value 11 | // Output: 12 | // 13 | } 14 | -------------------------------------------------------------------------------- /select/exam.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | /* 8 | 下面函数输出什么? 9 | 单选: 10 | - A: 函数输出“c1” 11 | - B: 函数输出“c2” 12 | - C: 函数输出“c1”、“c2” 13 | - D: 函数可能输出“c1”,也可能输出"c2" 14 | */ 15 | func SelectExam1() { 16 | c1 := make(chan int, 10) 17 | c2 := make(chan int, 10) 18 | c1 <- 1 19 | c2 <- 2 20 | 21 | select { 22 | case <-c1: 23 | fmt.Println("c1") 24 | case <-c2: 25 | fmt.Println("c2") 26 | } 27 | } 28 | 29 | /* 30 | 下面函数输出什么? 31 | 单选: 32 | - A: 函数输出“readable” 33 | - B: 函数输出"writable" 34 | - C: 函数什么也不输出,正常返回 35 | - D: 函数什么也不输出,陷入阻塞 36 | */ 37 | func SelectExam2() { 38 | c := make(chan int) 39 | 40 | select { 41 | case <-c: 42 | fmt.Printf("readable") 43 | case c <- 1: 44 | fmt.Println("writable") 45 | } 46 | } 47 | 48 | /* 49 | 下面函数输出什么? 50 | 单选: 51 | - A: 函数输出"1" 52 | - B: 函数输出空字符 53 | - C: 函数什么也不输出,陷入阻塞 54 | - D: 函数什么也不输出,发生panic 55 | */ 56 | func SelectExam3() { 57 | c := make(chan int, 10) 58 | c <- 1 59 | close(c) 60 | 61 | select { 62 | case d := <-c: 63 | fmt.Println(d) 64 | } 65 | } 66 | 67 | /* 68 | 下面函数输出什么? 69 | 单选: 70 | - A: 函数输出“1” 71 | - B: 函数输出“no data received” 72 | - C: 函数什么也不输出,陷入阻塞 73 | - D: 函数什么也不输出,发生panic 74 | */ 75 | func SelectExam4() { 76 | c := make(chan int, 10) 77 | c <- 1 78 | close(c) 79 | 80 | select { 81 | case d, ok := <-c: 82 | if !ok { 83 | fmt.Println("no data received") 84 | break 85 | } 86 | fmt.Println(d) 87 | } 88 | } 89 | 90 | /* 91 | 关于下面函数的描述,正确的是? 92 | 单选: 93 | - A: 编译错误,select语句非法 94 | - B: 运行时错误,panic 95 | - C: 函数陷入阻塞 96 | - D: 函数什么也不做,直接返回 97 | */ 98 | func SelectExam5() { 99 | select {} 100 | } 101 | 102 | /* 103 | 关于下面函数的描述,正确的是? 104 | 单选: 105 | - A: 函数会因为写值为nil的管道而被阻塞 106 | - B: 函数会因为写值为nil的管道而panic 107 | - C: 函数会从default出口返回 108 | - D: 编译错误,值为nil的管道不可以写 109 | */ 110 | func SelectExam6() { 111 | var c chan string 112 | select { 113 | case c <- "Hello": 114 | fmt.Println("sent") 115 | default: 116 | fmt.Println("default") 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /select/exam_test.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | // 结果:输出随机 4 | func ExampleSelectExam1() { 5 | SelectExam1() 6 | } 7 | 8 | // 结果:函数阻塞 9 | func ExampleSelectExam2() { 10 | SelectExam2() 11 | } 12 | 13 | func ExampleSelectExam3() { 14 | SelectExam3() 15 | // Output: 16 | // 1 17 | } 18 | 19 | func ExampleSelectExam4() { 20 | SelectExam4() 21 | // Output: 22 | // 1 23 | } 24 | 25 | // 结果:函数阻塞 26 | func ExampleSelectExam5() { 27 | SelectExam5() 28 | } 29 | 30 | func ExampleSelectExam6() { 31 | SelectExam6() 32 | // Output: 33 | // default 34 | } 35 | -------------------------------------------------------------------------------- /select/principle.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type scase struct { 9 | c string // chan 10 | elem unsafe.Pointer // data element 11 | kind uint16 12 | pc uintptr // race pc (for race detector / msan) 13 | releasetime int64 14 | } 15 | 16 | func SelectGo(cas0 *scase, order0 *uint16, ncases int) { 17 | cas1 := (*[1 << 16]scase)(unsafe.Pointer(cas0)) 18 | fmt.Printf("len(cas1)=%d, cap(cas1)=%d\n", len(cas1), cap(cas1)) 19 | 20 | order1 := (*[1 << 17]uint16)(unsafe.Pointer(order0)) 21 | fmt.Printf("len(order1)=%d, cap(order1)=%d\n", len(order1), cap(order1)) 22 | 23 | scases := cas1[:ncases:ncases] 24 | fmt.Printf("len(scases)=%d, cap(scases)=%d\n", len(scases), cap(scases)) 25 | pollorder := order1[:ncases:ncases] 26 | fmt.Printf("len(pollorder)=%d, cap(pollorder)=%d\n", len(pollorder), cap(pollorder)) 27 | lockorder := order1[ncases:][:ncases:ncases] 28 | fmt.Printf("len(lockorder)=%d, cap(lockorder)=%d\n", len(lockorder), cap(lockorder)) 29 | } 30 | 31 | func WriteNilChannle() { 32 | var c chan string 33 | select { 34 | case c <- "hello": // 向值为nil的管道写数据不会触发panic 35 | fmt.Println("true") 36 | default: 37 | fmt.Println("default") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /select/principle_test.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | func ExampleSelectGo() { 4 | var cas0 = [2]scase{ 5 | {c: "1"}, 6 | {c: "2"}, 7 | } 8 | 9 | var order0 = [4]uint16{} 10 | 11 | SelectGo(&cas0[0], &order0[0], 2) 12 | // Output: 13 | // len(cas1)=65536, cap(cas1)=65536 14 | // len(order1)=131072, cap(order1)=131072 15 | // len(scases)=2, cap(scases)=2 16 | // len(pollorder)=2, cap(pollorder)=2 17 | // len(lockorder)=2, cap(lockorder)=2 18 | } 19 | 20 | func ExampleWriteNilChannle() { 21 | WriteNilChannle() 22 | // Output: 23 | // default 24 | } 25 | -------------------------------------------------------------------------------- /select/select.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // select 只能做用于管道读写 9 | func SelectForChan(c chan string) { 10 | var recv string 11 | send := "Hello" 12 | 13 | select { 14 | case recv = <-c: 15 | fmt.Printf("received %s\n", recv) 16 | case c <- send: 17 | fmt.Printf("sent %s\n", send) 18 | } 19 | } 20 | 21 | // select 可以接受0~2个返回值 22 | func SelectAssign(c chan string) { 23 | select { 24 | case <-c: // 0个变量 25 | fmt.Printf("0") 26 | case d := <-c: // 1个变量 27 | fmt.Printf("1: received %s\n", d) 28 | case d, ok := <-c: // 2个变量 29 | if !ok { 30 | fmt.Printf("no data found") 31 | break 32 | } 33 | fmt.Printf("2: received %s\n", d) 34 | } 35 | } 36 | 37 | func SelectDefault() { 38 | c := make(chan string) 39 | select { 40 | case <-c: 41 | fmt.Printf("received\n") 42 | default: 43 | fmt.Printf("no data found in default\n") 44 | } 45 | } 46 | 47 | func SelectChanStillBlock() { 48 | ch := make(chan int, 10) 49 | select { 50 | case _, ok := <-ch: // 此处仍然会阻塞 51 | fmt.Printf("never reached if channel is open. %v\n", ok) 52 | case <-time.After(10 * time.Millisecond): 53 | fmt.Printf("time out") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /select/select_test.go: -------------------------------------------------------------------------------- 1 | package _select 2 | 3 | func ExampleSelectForChan() { 4 | c := make(chan string, 1) 5 | // 由于chan中没有数据,select只会响应写分支 6 | SelectForChan(c) 7 | <-c 8 | // Output: 9 | // sent Hello 10 | } 11 | 12 | func ExampleSelectForChan2() { 13 | c := make(chan string, 1) 14 | c <- "Hello" 15 | // 由于chan中已有1个数据(缓冲区满,select只会响应读分支) 16 | SelectForChan(c) 17 | // Output: 18 | // received Hello 19 | } 20 | 21 | func ExampleSelectForChan3() { 22 | // c := make(chan string) 23 | // var c chan string 24 | 25 | // 由于chan无缓冲区,且无协程向其写入和读出,那么select永久阻塞 26 | // SelectForChan(c) // 注释掉,永远阻塞 27 | // Output: 28 | // received Hello 29 | } 30 | 31 | // 两个case 语句随机执行 32 | func ExampleSelectForChan4() { 33 | c := make(chan string, 2) 34 | c <- "Hello" 35 | SelectForChan(c) 36 | } 37 | 38 | // 3个case 语句随机执行 39 | func ExampleSelectAssign() { 40 | c := make(chan string, 1) 41 | c <- "Hello" 42 | SelectAssign(c) 43 | } 44 | 45 | // 关闭的channel,三个case语句都有机会执行,但只有返回两个值时才能感知到close。 46 | func ExampleSelectAssign2() { 47 | c := make(chan string) 48 | close(c) 49 | SelectAssign(c) 50 | } 51 | 52 | func ExampleSelectDefault() { 53 | SelectDefault() 54 | // Output: 55 | // no data found in default 56 | } 57 | 58 | func ExampleSelectChanStillBlock() { 59 | SelectChanStillBlock() 60 | // Output: 61 | // time out 62 | } 63 | -------------------------------------------------------------------------------- /slice/exam.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | import "fmt" 4 | 5 | /* 6 | 下面函数输出什么? 7 | */ 8 | func SliceCap() { 9 | var array [10]int 10 | var slice = array[5:6] 11 | 12 | fmt.Printf("len(slice) = %d\n", len(slice)) 13 | fmt.Printf("cap(slice) = %d\n", cap(slice)) 14 | } 15 | 16 | /* 17 | 下面函数输出什么? 18 | 单选: 19 | - A: [2, 3] [2, 3, 4] 20 | - B: [1, 2] [1, 2, 3] 21 | - C: [1, 2] [2, 3, 4] 22 | - D: [2, 3, 1] [2, 3, 4, 1] 23 | */ 24 | func SliceRise(s []int) { 25 | s = append(s, 0) 26 | for i := range s { 27 | s[i]++ 28 | } 29 | } 30 | 31 | func SlicePrint() { 32 | s1 := []int{1, 2} 33 | s2 := s1 34 | s2 = append(s2, 3) 35 | SliceRise(s1) 36 | SliceRise(s2) 37 | fmt.Println(s1, s2) 38 | } 39 | 40 | /* 41 | 关于下面函数的描述,正确的是? 42 | 43 | 单选: 44 | - A: append函数在操作切片s和s1时发生了扩容 45 | - B: 编译错误,不可以对切片元素取址 46 | - C: 函数输出"true" 47 | - D: 函数输出"false" 48 | */ 49 | func SliceExtend() { 50 | s := make([]int, 0, 10) 51 | s1 := append(s, 1, 2, 3) 52 | s2 := append(s1, 4) 53 | 54 | fmt.Println(&s1[0] == &s2[0]) 55 | } 56 | 57 | /* 58 | 下面函数输出什么? 59 | */ 60 | func SliceExpress() { 61 | orderLen := 5 62 | order := make([]uint16, 2*orderLen) 63 | 64 | pollorder := order[:orderLen:orderLen] 65 | lockorder := order[orderLen:][:orderLen:orderLen] 66 | 67 | fmt.Println("len(pollorder) = ", len(pollorder)) 68 | fmt.Println("cap(pollorder) = ", cap(pollorder)) 69 | fmt.Println("len(lockorder) = ", len(lockorder)) 70 | fmt.Println("cap(lockorder) = ", cap(lockorder)) 71 | } 72 | -------------------------------------------------------------------------------- /slice/exam_test.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | func ExampleSliceCap() { 4 | SliceCap() 5 | // Output: 6 | // len(slice) = 1 7 | // cap(slice) = 5 8 | } 9 | 10 | func ExampleSlicePrint() { 11 | SlicePrint() 12 | // Output: 13 | // [1 2] [2 3 4] 14 | } 15 | 16 | func ExampleSliceExtend() { 17 | SliceExtend() 18 | // Output: 19 | // true 20 | } 21 | 22 | func ExampleSliceExpress() { 23 | SliceExpress() 24 | // Output: 25 | // len(pollorder) = 5 26 | // cap(pollorder) = 5 27 | // len(lockorder) = 5 28 | // cap(lockorder) = 5 29 | } 30 | -------------------------------------------------------------------------------- /slice/extend.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | // 测试拷贝切片时遍历和内置函数性能差异 4 | func CopyByIteration(origin []string) []string { 5 | ret := make([]string, len(origin)) 6 | for i := range origin { 7 | ret[i] = origin[i] 8 | } 9 | 10 | return ret 11 | } 12 | 13 | // 测试拷贝切片时遍历和内置函数性能差异 14 | func CopyByBuiltIn(origin []string) []string { 15 | ret := make([]string, len(origin)) 16 | copy(ret, origin) 17 | return ret 18 | } 19 | -------------------------------------------------------------------------------- /slice/extend_test.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var s []string 8 | 9 | func setSamples() { 10 | s = []string{"aaaaa", "bbbbb", "ccccc", "dddddd", "eeeeee", "fffff", "ggggg", "hhhhh", "iiiii", "jjjjj", "kkkkk", "lllll", 11 | "mmmmm", "nnnnn", "ooooo", "ppppp", "qqqqq", "rrrrr", "sssss", "ttttt", "uuuuu", "vvvvv", "wwwww", "xxxxx", "yyyyy", "zzzzz"} 12 | } 13 | 14 | func BenchmarkCopyByIteration(b *testing.B) { 15 | setSamples() 16 | 17 | for i := 0; i < b.N; i++ { 18 | CopyByIteration(s) 19 | } 20 | } 21 | 22 | func BenchmarkCopyByBuiltIn(b *testing.B) { 23 | setSamples() 24 | 25 | for i := 0; i < b.N; i++ { 26 | CopyByBuiltIn(s) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /slice/slice.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | import "fmt" 4 | 5 | func SliceDeclare() { 6 | var s []int 7 | fmt.Println(s == nil) // true 8 | } 9 | 10 | func SliceLiteral() { 11 | s1 := []int{} // 空切片 12 | s2 := []int{1, 2, 3} // 长度为3的切片 13 | fmt.Println(s1 == nil) // false 14 | fmt.Println(s2 == nil) // false 15 | } 16 | 17 | // make不指定空间时,空间默认等于长度 18 | func SliceInitMake() { 19 | s1 := make([]int, 12) // 指定长度 20 | s2 := make([]int, 10, 100) // 指定长度和空间 21 | 22 | fmt.Println(s1 == nil) // false 23 | fmt.Println(s2 == nil) // false 24 | } 25 | 26 | func SliceCut() { 27 | array := [5]int{1, 2, 3, 4, 5} 28 | s1 := array[0:2] // 从数组切取 29 | s2 := s1[0:1] // 从切片切取 30 | fmt.Println(s1) // [1 2] 31 | fmt.Println(s2) // [1] 32 | } 33 | 34 | func SliceInitNew() { 35 | s := *new([]int) 36 | fmt.Println(s == nil) // true 37 | } 38 | 39 | func SliceAppend() { 40 | s := make([]int, 0) 41 | s = append(s, 1) // 添加1个元素 42 | s = append(s, 2, 3, 4) // 添加多个元素 43 | s = append(s, []int{5, 6}...) // 添加一个切片 44 | fmt.Println(s) // [1 2 3 4 5 6] 45 | } 46 | -------------------------------------------------------------------------------- /slice/slice_test.go: -------------------------------------------------------------------------------- 1 | package _slice 2 | 3 | func ExampleSliceDeclare() { 4 | SliceDeclare() 5 | // Output: 6 | // true 7 | } 8 | 9 | func ExampleSliceLiteral() { 10 | SliceLiteral() 11 | // Output: 12 | // false 13 | // false 14 | } 15 | 16 | func ExampleSliceInitMake() { 17 | SliceInitMake() 18 | // Output: 19 | // false 20 | // false 21 | } 22 | 23 | func ExampleSliceCut() { 24 | SliceCut() 25 | // Output: 26 | // [1 2] 27 | // [1] 28 | } 29 | 30 | func ExampleSliceInitNew() { 31 | SliceInitNew() 32 | // Output: 33 | // true 34 | } 35 | 36 | func ExampleSliceAppend() { 37 | SliceAppend() 38 | // Output: 39 | // [1 2 3 4 5 6] 40 | } 41 | -------------------------------------------------------------------------------- /string/exam.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import "fmt" 4 | 5 | /* 6 | 关于下面函数中字符串长度描述正确的是? 7 | 单选: 8 | - A:字符串长度表示字符个数,长度为2 9 | - B:字符串长度表示Unicode编码字节数,长度大于2 10 | - C:不可以针对中文字符计算长度 11 | - D:不确定,与运行环境有关 12 | */ 13 | func StringExam1() { 14 | var s string 15 | s = "中国" 16 | fmt.Println(len(s)) 17 | } 18 | 19 | /* 20 | 关于字符串的描述正确的是? 21 | 22 | 单选: 23 | - A:如果string为nil,那么其长度为0 24 | - B:不存在值为nil的string 25 | */ 26 | 27 | /* 28 | 下面关于字符串的描述正确的是? 29 | 单选: 30 | - A: 可以使用下标修改string的内容 31 | - B: 字符串不可以修改 32 | */ 33 | -------------------------------------------------------------------------------- /string/exam_test.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | func ExampleStringExam1() { 4 | StringExam1() 5 | // Output: 6 | // 6 7 | } 8 | -------------------------------------------------------------------------------- /string/extend.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // StringFormat 演示`%s`和`%q`格式的区别 8 | // 更多参考信息:https://github.com/kubernetes-sigs/kubefed/pull/1216 9 | func StringFormat() { 10 | var s string 11 | s = "https://example.com:port80" 12 | fmt.Printf("format-s: %s\n", s) 13 | fmt.Printf("format-q: %q\n", s) 14 | } 15 | -------------------------------------------------------------------------------- /string/extend_test.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | func ExampleStringFormat() { 4 | StringFormat() 5 | // Output: 6 | // format-s: https://example.com:port80 7 | // format-q: "https://example.com:port80" 8 | } 9 | -------------------------------------------------------------------------------- /string/principle.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import "fmt" 4 | 5 | func GetUnicode() { 6 | s := "中国" 7 | for i := 0; i < len(s); i++ { 8 | fmt.Println(s[i]) 9 | } 10 | } 11 | 12 | func GetAscii() { 13 | s := "hi" 14 | for i := 0; i < len(s); i++ { 15 | fmt.Println(s[i]) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /string/principle_test.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | func ExampleGetUnicode() { 4 | GetUnicode() 5 | // Output: 6 | // 228 7 | // 184 8 | // 173 9 | // 229 10 | // 155 11 | // 189 12 | } 13 | 14 | func ExampleGetAscii() { 15 | GetAscii() 16 | // Output: 17 | // 104 18 | // 105 19 | } 20 | -------------------------------------------------------------------------------- /string/string.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import "fmt" 4 | 5 | func StringDoubleQuotationMarks() { 6 | s := "Hi, \nthis is \"RainbowMango\"." 7 | fmt.Println(s) 8 | } 9 | 10 | func StringBackslash() { 11 | s := `Hi, 12 | this is "RainbowMango".` 13 | fmt.Println(s) 14 | } 15 | 16 | func StringConnectSample1() string { 17 | var s string 18 | s = s + "a" + "b" 19 | return s 20 | } 21 | 22 | func StringConnectSample2() string { 23 | var s string 24 | s = s + "a" 25 | s = s + "b" 26 | return s 27 | } 28 | 29 | func StringToByte() { 30 | b := []byte{'H', 'e', 'l', 'l', 'o'} 31 | s := string(b) 32 | fmt.Println(s) // Hello 33 | } 34 | 35 | func ByteToString() { 36 | s := "Hello" 37 | b := []byte(s) 38 | fmt.Println(b) // [72 101 108 108 111] 39 | } 40 | 41 | func StringIteration() { 42 | s := "中国" 43 | for index, value := range s { 44 | fmt.Printf("index: %d, value: %c\n", index, value) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /string/string_test.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import "testing" 4 | 5 | /* 6 | TODO: 分析测试失败原因 7 | // Output: 8 | // Hi, 9 | // this is "RainbowMango". 10 | */ 11 | func ExampleStringDoubleQuotationMarks() { 12 | StringDoubleQuotationMarks() 13 | } 14 | 15 | /* 16 | TODO: 分析测试失败原因 17 | // Output: 18 | // Hi, 19 | // This is "RainbowMango". 20 | */ 21 | func ExampleStringBackslash() { 22 | StringBackslash() 23 | } 24 | 25 | func BenchmarkStringConnectSample1(b *testing.B) { 26 | for i := 0; i < b.N; i++ { 27 | StringConnectSample1() 28 | } 29 | } 30 | 31 | func BenchmarkStringConnectSample2(b *testing.B) { 32 | for i := 0; i < b.N; i++ { 33 | StringConnectSample2() 34 | } 35 | } 36 | 37 | func ExampleStringToByte() { 38 | StringToByte() 39 | // Output: 40 | // Hello 41 | } 42 | 43 | func ExampleByteToString() { 44 | ByteToString() 45 | // Output: 46 | // [72 101 108 108 111] 47 | } 48 | 49 | func ExampleStringIteration() { 50 | StringIteration() 51 | // Output: 52 | // index: 0, value: 中 53 | // index: 3, value: 国 54 | } 55 | -------------------------------------------------------------------------------- /string/strings.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func Contains() { 9 | s := "Hello World!" 10 | sub := "World" 11 | if strings.Contains(s, sub) { 12 | fmt.Printf("%s contains %s\n", s, sub) 13 | } 14 | } 15 | 16 | func Trim() { 17 | s := "abba" 18 | cutset := "ba" 19 | s = strings.Trim(s, cutset) 20 | fmt.Printf("Trimed: %s", s) 21 | } 22 | 23 | func Replace() { 24 | s := "Hello, Hello, Hello" 25 | old := "Hello" 26 | new := "hello" 27 | s = strings.Replace(s, old, new, 2) 28 | fmt.Printf("Replaced: %s\n", s) 29 | } 30 | -------------------------------------------------------------------------------- /string/strings_test.go: -------------------------------------------------------------------------------- 1 | package _string 2 | 3 | func ExampleContains() { 4 | Contains() 5 | // Output: 6 | // Hello World! contains World 7 | } 8 | 9 | func ExampleTrim() { 10 | Trim() 11 | // Output: 12 | // Trimed: 13 | } 14 | 15 | func ExampleReplace() { 16 | Replace() 17 | // Output: 18 | // Replaced: hello, hello, Hello 19 | } 20 | -------------------------------------------------------------------------------- /struct/exam.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | /* 9 | 关于下面类型的描述,正确的是? 10 | 单选: 11 | - A:age为私有字段,只能通过类型方法访问 12 | - B:Name和age字段在可见性上没有区别 13 | - C:age为私有字段,变量初始化时不能直接赋值 14 | - D:当前package中,Name和age字段在可见性上没有区别 15 | */ 16 | type People struct { 17 | Name string 18 | age int 19 | } 20 | 21 | func (p *People) SetName(name string) { 22 | p.Name = name 23 | } 24 | 25 | func (p *People) SetAge(age int) { 26 | p.age = age 27 | } 28 | 29 | func (p *People) GetAge() int { 30 | return p.age 31 | } 32 | 33 | /* 34 | 关于下面代码的描述,正确的是? 35 | 单选: 36 | - A: 编译错误,类型和类型指针不能同时作为方法接收者 37 | - B: SetName()无法修改名字 38 | - C: SetAge()无法修改年龄 39 | - D: SetName()和 SetAge()工作正常 40 | */ 41 | type Kid struct { 42 | Name string 43 | Age int 44 | } 45 | 46 | func (k Kid) SetName(name string) { 47 | k.Name = name 48 | } 49 | 50 | func (k *Kid) SetAge(age int) { 51 | k.Age = age 52 | } 53 | 54 | func KidFoo() { 55 | var k Kid 56 | k.SetName("Marco") 57 | k.SetAge(3) 58 | fmt.Printf("Name: %s, Age: %d\n", k.Name, k.Age) 59 | } 60 | 61 | /* 62 | 使用标准库json包操作下面结构体时,下面描述正确的是: 63 | ```go 64 | f := Fruit{Name: "apple", Color: "red"} 65 | s := `{"Name":"banana","Weight":100}` 66 | ``` 67 | 68 | 单选: 69 | - A: json.Marshal(f)时会忽略Color字段 70 | - B: json.Marshal(f)时不会被忽略Color字段 71 | - C: json.Unmarshal([]byte(s), &f)时会忽略Color字段 72 | - D: json.Unmarshal([]byte(s), &f)时会出错,因为Fruit类型没有Weight字段 73 | */ 74 | 75 | type Fruit struct { 76 | Name string `json:"name"` 77 | Color string `json:"color,omitempty"` 78 | } 79 | 80 | var f = Fruit{Name: "apple", Color: "red"} 81 | var s = `{"Name":"banana","Weight":100}` 82 | 83 | func MetaFoo() { 84 | if b, err := json.Marshal(f); err != nil { 85 | fmt.Println("unexpected error: ", err.Error()) 86 | } else { 87 | fmt.Printf("%s\n", string(b)) 88 | } 89 | 90 | fruit := Fruit{} 91 | s := `{"Name":"banana","Weight":100}` 92 | if err := json.Unmarshal([]byte(s), &fruit); err != nil { 93 | fmt.Println("unexpected error: ", err.Error()) 94 | } else { 95 | fmt.Printf("Name: %s, Color: %s\n", fruit.Name, fruit.Color) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /struct/exam_test.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | func ExampleKidFoo() { 4 | KidFoo() 5 | // Output: 6 | // Name: , Age: 3 7 | } 8 | 9 | func ExampleMetaFoo() { 10 | MetaFoo() 11 | // Output: 12 | // {"name":"apple","color":"red"} 13 | // Name: banana, Color: 14 | } 15 | -------------------------------------------------------------------------------- /struct/promoted.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | import "fmt" 4 | 5 | type Animal struct { 6 | Name string 7 | } 8 | 9 | func (a *Animal) SetName(name string) { 10 | a.Name = name 11 | } 12 | 13 | type Cat struct { 14 | Animal 15 | } 16 | 17 | func EmbeddedFoo() { 18 | c := Cat{} 19 | 20 | c.SetName("A") 21 | fmt.Printf("Name: %s\n", c.Name) // A 22 | 23 | c.Animal.SetName("a") 24 | fmt.Printf("Name: %s\n", c.Name) // a 25 | 26 | c.Animal.Name = "B" 27 | fmt.Printf("Name: %s\n", c.Name) // B 28 | 29 | c.Name = "b" 30 | fmt.Printf("Name: %s\n", c.Name) // b 31 | } 32 | -------------------------------------------------------------------------------- /struct/promoted_test.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | func ExampleEmbeddedFoo() { 4 | EmbeddedFoo() 5 | // Output: 6 | // Name: A 7 | // Name: a 8 | // Name: B 9 | // Name: b 10 | } 11 | -------------------------------------------------------------------------------- /struct/receiver.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | import "fmt" 4 | 5 | type Student struct { 6 | Name string 7 | } 8 | 9 | // 作用于Student的拷贝对象,修改不会反映到原对象 10 | func (s Student) SetName(name string) { 11 | s.Name = name 12 | } 13 | 14 | // 作用于Student的指针对象,修改会反映到原对象 15 | func (s *Student) UpdateName(name string) { 16 | s.Name = name 17 | } 18 | 19 | func Receiver() { 20 | s := Student{} 21 | s.SetName("Rainbow") 22 | fmt.Printf("Name: %s\n", s.Name) // empty 23 | s.UpdateName("Rainbow") 24 | fmt.Printf("Name: %s\n", s.Name) // Rainbow 25 | } 26 | -------------------------------------------------------------------------------- /struct/receiver_test.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | /* 4 | 暂不清楚为什么测试会失败 5 | // Output: 6 | // Name: 7 | // Name: Rainbow 8 | */ 9 | func ExampleReceiver() { 10 | Receiver() 11 | } 12 | -------------------------------------------------------------------------------- /struct/struct.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // 嵌入字段类型名将作为字段名存在 9 | func EmbeddedField() { 10 | type A struct { 11 | a1 int 12 | } 13 | type B struct { 14 | b1 int 15 | A // embedded field 16 | } 17 | 18 | b := B{} 19 | t := reflect.TypeOf(b) 20 | for i := 0; i < t.NumField(); i++ { 21 | fmt.Printf("field-%d, Name: %s, isEmbedded: %v\n", i, t.Field(i).Name, t.Field(i).Anonymous) 22 | } 23 | } 24 | 25 | // 非空fields名称必须唯一 26 | func FieldsUnique() { 27 | type A struct { 28 | a1 int 29 | _ int // blank field 30 | _ int // blank field 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /struct/struct_test.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | func ExampleEmbeddedField() { 4 | EmbeddedField() 5 | // Output: 6 | // field-0, Name: b1, isEmbedded: false 7 | // field-1, Name: A, isEmbedded: true 8 | } 9 | -------------------------------------------------------------------------------- /struct/tag.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type TypeMeta struct { 9 | Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"` 10 | APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,2,opt,name=apiVersion"` 11 | } 12 | 13 | func PrintTag() { 14 | t := TypeMeta{} 15 | ty := reflect.TypeOf(t) 16 | 17 | for i := 0; i < ty.NumField(); i++ { 18 | fmt.Printf("Field: %s, Tag: %s\n", ty.Field(i).Name, ty.Field(i).Tag.Get("json")) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /struct/tag_test.go: -------------------------------------------------------------------------------- 1 | package _struct 2 | 3 | func ExamplePrintTag() { 4 | PrintTag() 5 | // Output: 6 | // Field: Kind, Tag: kind,omitempty 7 | // Field: APIVersion, Tag: apiVersion,omitempty 8 | } 9 | -------------------------------------------------------------------------------- /sugar/shortVariableDeclarations.go: -------------------------------------------------------------------------------- 1 | package sugar 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // rule := "Short variable declarations" // syntax error: non-declaration statement outside function body 8 | 9 | func fun1() { 10 | i := 0 11 | i, j := 1, 2 12 | fmt.Printf("i = %d, j = %d\n", i, j) 13 | } 14 | 15 | func fun2(i int) { 16 | // i := 0 // 无法通过编译:no new variable on left side of := 17 | fmt.Println(i) 18 | } 19 | 20 | func fun3() { 21 | i, j := 0, 0 22 | if true { 23 | j, k := 1, 1 24 | fmt.Printf("j = %d, k = %d\n", j, k) 25 | } 26 | fmt.Printf("i = %d, j = %d\n", i, j) 27 | } 28 | 29 | func nextField() (field int, err error) { 30 | return 1, nil 31 | } 32 | 33 | /* 34 | 下面代码变量未使用编译不通过,仅用于说明用法 35 | func Redeclare() { 36 | field, err:= nextField() // 1号err 37 | 38 | if field == 1{ 39 | field, err:= nextField() // 2号err 40 | newField, err := nextField() // 3号err 41 | ... 42 | } 43 | ... 44 | } 45 | */ 46 | func SugerPackage() { 47 | fun1() 48 | fun3() 49 | } 50 | -------------------------------------------------------------------------------- /sugar/variadic.go: -------------------------------------------------------------------------------- 1 | package sugar 2 | 3 | import "fmt" 4 | 5 | func Greeting(prefix string, who ...string) { 6 | if who == nil { 7 | fmt.Printf("Nobody to say hi.") 8 | return 9 | } 10 | 11 | for _, people := range who { 12 | fmt.Printf("%s %s\n", prefix, people) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sugar/variadic_test.go: -------------------------------------------------------------------------------- 1 | package sugar 2 | 3 | // 可变参数,调用时可以不填值 4 | func ExampleGreetingWithoutParameter() { 5 | Greeting("nobody") 6 | // OutPut: 7 | // Nobody to say hi. 8 | } 9 | 10 | // 可变参数传值 11 | func ExampleGreetingWithParameter() { 12 | Greeting("hello:", "Joe", "Anna", "Eileen") 13 | // OutPut: 14 | // hello: Joe 15 | // hello: Anna 16 | // hello: Eileen 17 | } 18 | 19 | // 可变参数传切片 20 | func ExampleGreetingWithSlice() { 21 | guest := []string{"Joe", "Anna", "Eileen"} 22 | Greeting("hello:", guest...) 23 | // OutPut: 24 | // hello: Joe 25 | // hello: Anna 26 | // hello: Eileen 27 | } 28 | -------------------------------------------------------------------------------- /syncmap/demonstrate.go: -------------------------------------------------------------------------------- 1 | package syncmap 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | func Demonstrate() { 9 | // sync.Map 的零值为空的map,声明后就可以直接使用,不需要再初始化 10 | var m sync.Map 11 | 12 | m.Store("Jim", 80) // 写入Jim的成绩 13 | m.Store("Kevin", 90) // 写入Kevin的成绩 14 | m.Store("Jim", 90) // 将修改Jim的成绩为90 15 | 16 | score, _ := m.Load("Jim") // 查询Jim的成绩 17 | fmt.Printf("Jim's score: %d\n", score.(int)) 18 | 19 | m.Delete("Jim") // 删除Jim 20 | } 21 | 22 | func DemonstrateTypeUnsafe() { 23 | var m sync.Map 24 | m.Store("Kevin", 90) // 键类型为 string 25 | m.Store(80, "Kevin") // 键类型为 int 26 | 27 | fmt.Println("school report:") 28 | m.Range(func(key, value any) bool { 29 | fmt.Printf("Name: %s, score: %d\n", key.(string), value.(int)) // panic 30 | return true 31 | }) 32 | } 33 | 34 | // DemonstrateCannotTransfer 用于演示sync.Map不能传递。 35 | // 注:个人对编译器无法拦截此风险代码感到诧异,IDE反而可以给出告警 36 | func DemonstrateCannotTransfer() { 37 | var m sync.Map 38 | m.Store("Jim", 80) // 写入Jim的成绩 39 | m.Store("Kevin", 90) // 写入Kevin的成绩 40 | 41 | // 'func' passes a lock by the value: type 'sync.Map' contains 'sync.Mutex' which is 'sync.Locker' 42 | funcFoo := func(m sync.Map) { 43 | m.Range(func(key, value any) bool { 44 | fmt.Println("Name:", key, "Score:", value) 45 | return true 46 | }) 47 | } 48 | 49 | funcFoo(m) 50 | } 51 | 52 | // DemonstrateInsertUncomparableMap 演示不能存储不可比较类型,即便内部map类型为map[any]*entry 53 | func DemonstrateInsertUncomparableMap() { 54 | nativeMap := make(map[string]int) 55 | var m sync.Map 56 | m.Store(nativeMap, "should panic") // panic: runtime error: hash of unhashable type map[string]int 57 | m.Load(nativeMap) 58 | } 59 | 60 | func DemonstrateInsertUncomparableFunc() { 61 | funcFoo := func() { 62 | fmt.Println("I'm a func") 63 | } 64 | var m sync.Map 65 | m.Store(funcFoo, "should panic") // panic: runtime error: hash of unhashable type func() 66 | } 67 | -------------------------------------------------------------------------------- /syncmap/demonstrate_test.go: -------------------------------------------------------------------------------- 1 | package syncmap 2 | 3 | func ExampleDemonstrate() { 4 | Demonstrate() 5 | // output: 6 | // Jim's score: 90 7 | } 8 | 9 | /* 10 | 该示例仅用于演示sync.Map类型不安全的特点,会引发panic 11 | func ExampleDemonstrateTypeUnsafe() { 12 | DemonstrateTypeUnsafe() 13 | // output: 14 | // panic 15 | } 16 | */ 17 | 18 | func ExampleDemonstrateCannotTransfer() { 19 | DemonstrateCannotTransfer() 20 | // output: 21 | // Name: Jim Score: 80 22 | // Name: Kevin Score: 90 23 | } 24 | 25 | /* 26 | 该示例仅用于演示sync.Map不能存储map的事实 27 | func ExampleDemonstrateInsertUncomparable() { 28 | DemonstrateInsertUncomparableMap() 29 | // output: 30 | // 31 | } 32 | */ 33 | 34 | /* 35 | 该示例用于演示sync.Map不能存储函数的事实 36 | func ExampleDemonstrateInsertUncomparableFunc() { 37 | DemonstrateInsertUncomparableFunc() 38 | // output: 39 | // 40 | } 41 | */ 42 | -------------------------------------------------------------------------------- /trap/loop/reference.go: -------------------------------------------------------------------------------- 1 | package loop 2 | 3 | import "fmt" 4 | 5 | func ReferenceLoopIteratorVariable() { 6 | var out []*int 7 | for i := 0; i < 3; i++ { 8 | out = append(out, &i) 9 | } 10 | fmt.Println("Values:", *out[0], *out[1], *out[2]) 11 | fmt.Println("cap:", cap(out)) 12 | } 13 | -------------------------------------------------------------------------------- /trap/loop/reference_test.go: -------------------------------------------------------------------------------- 1 | package loop 2 | 3 | func ExampleReferenceLoopIteratorVariable() { 4 | ReferenceLoopIteratorVariable() 5 | // OutPut: 6 | // Values: 3 3 3 7 | // cap: 4 8 | } 9 | -------------------------------------------------------------------------------- /trap/loop2/loop2.go: -------------------------------------------------------------------------------- 1 | package loop2 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func foo() { 9 | var a []int 10 | a = append(a, 1, 2, 3) 11 | for _, val := range a { 12 | go func() { 13 | fmt.Println(val) 14 | }() 15 | } 16 | 17 | time.Sleep(1 * time.Second) 18 | } 19 | -------------------------------------------------------------------------------- /trap/loop2/loop2_test.go: -------------------------------------------------------------------------------- 1 | package loop2 2 | 3 | func ExampleFoo() { 4 | foo() 5 | // OutPut: 6 | // 3 7 | // 3 8 | // 3 9 | } 10 | --------------------------------------------------------------------------------