├── src └── puzzlers │ ├── go.mod │ ├── article2 │ ├── q0 │ │ └── demo1.go │ ├── q1 │ │ └── demo2.go │ └── q3 │ │ └── demo3.go │ ├── article19 │ ├── q0 │ │ └── demo47.go │ ├── q4 │ │ └── demo51.go │ ├── q2 │ │ └── demo49.go │ ├── q1 │ │ └── demo48.go │ └── q3 │ │ └── demo50.go │ ├── article3 │ ├── q1 │ │ ├── demo4_lib.go │ │ └── demo4.go │ ├── q2 │ │ ├── lib │ │ │ └── demo5_lib.go │ │ └── demo5.go │ └── q4 │ │ ├── lib │ │ ├── demo6_lib.go │ │ └── internal │ │ │ └── internal.go │ │ └── demo6.go │ ├── article16 │ ├── q1 │ │ └── demo38.go │ ├── q2 │ │ └── demo39.go │ └── q3 │ │ └── demo40.go │ ├── article20 │ ├── q3 │ │ ├── demo54_test.go │ │ └── demo54.go │ ├── q0 │ │ ├── demo52.go │ │ └── demo52_test.go │ └── q2 │ │ ├── demo53.go │ │ └── demo53_test.go │ ├── article29 │ ├── q2 │ │ └── demo74.go │ └── q1 │ │ └── demo73.go │ ├── article37 │ ├── q5 │ │ ├── usage1 │ │ │ └── demo100.go │ │ └── usage2 │ │ │ └── demo101.go │ ├── common │ │ ├── op │ │ │ ├── cpu.go │ │ │ ├── mem.go │ │ │ └── block.go │ │ └── common.go │ ├── q1 │ │ └── demo96.go │ ├── q2 │ │ └── demo97.go │ ├── q3 │ │ └── demo98.go │ └── q4 │ │ └── demo99.go │ ├── article5 │ ├── q2 │ │ └── demo11.go │ └── q1 │ │ └── demo10.go │ ├── article10 │ ├── q0 │ │ └── demo20.go │ ├── q2 │ │ └── demo21.go │ └── q3 │ │ └── demo22.go │ ├── article12 │ ├── q0 │ │ └── demo26.go │ ├── q1 │ │ └── demo27.go │ └── q3 │ │ └── demo28.go │ ├── article4 │ ├── q3 │ │ └── demo9.go │ ├── q2 │ │ └── demo8.go │ └── q1 │ │ └── demo7.go │ ├── article21 │ ├── q3 │ │ ├── demo57_test.go │ │ └── demo57.go │ ├── q1 │ │ ├── demo55.go │ │ └── demo55_test.go │ └── q2 │ │ ├── demo56.go │ │ └── demo56_test.go │ ├── article35 │ ├── q0 │ │ └── demo90.go │ ├── q2 │ │ └── demo92.go │ └── q1 │ │ └── demo91.go │ ├── article9 │ ├── q3 │ │ └── demo19.go │ └── q1 │ │ └── demo18.go │ ├── article15 │ ├── q2 │ │ └── demo36.go │ ├── q3 │ │ └── demo37.go │ └── q1 │ │ └── demo35.go │ ├── article7 │ ├── q3 │ │ └── demo17.go │ ├── q1 │ │ └── demo15.go │ └── q2 │ │ └── demo16.go │ ├── article17 │ ├── q2 │ │ └── demo42.go │ ├── q1 │ │ └── demo41.go │ └── q3 │ │ └── demo43.go │ ├── article31 │ ├── q0 │ │ └── demo78.go │ ├── q2 │ │ └── demo79.go │ └── q3 │ │ └── demo80.go │ ├── article11 │ ├── q3 │ │ └── demo25.go │ ├── q1 │ │ └── demo23.go │ └── q2 │ │ └── demo24.go │ ├── article30 │ ├── q2 │ │ └── demo76.go │ ├── q1 │ │ └── demo75.go │ └── q3 │ │ └── demo77.go │ ├── article14 │ ├── q0 │ │ └── demo31.go │ ├── q2 │ │ └── demo33.go │ ├── q3 │ │ └── demo34.go │ └── q1 │ │ └── demo32.go │ ├── article18 │ ├── q0 │ │ └── demo44.go │ ├── q2 │ │ └── demo46.go │ └── q1 │ │ └── demo45.go │ ├── article36 │ ├── q0 │ │ └── demo93.go │ ├── q2 │ │ └── demo95.go │ └── q1 │ │ └── demo94.go │ ├── article6 │ ├── q1 │ │ └── demo12.go │ ├── q2 │ │ └── demo13.go │ └── q3 │ │ └── demo14.go │ ├── article26 │ ├── q1 │ │ └── demo68.go │ ├── q0 │ │ └── demo67.go │ └── q4 │ │ └── demo69.go │ ├── article32 │ ├── q2 │ │ └── demo83.go │ ├── q0 │ │ └── demo81.go │ └── q1 │ │ └── demo82.go │ ├── article23 │ ├── q1 │ │ └── demo61.go │ └── q3 │ │ └── demo62.go │ ├── article25 │ ├── q0 │ │ └── demo65.go │ └── q2 │ │ └── demo66.go │ ├── article34 │ ├── q3 │ │ └── demo89.go │ ├── q2 │ │ └── demo88.go │ └── q1 │ │ └── demo87.go │ ├── article13 │ ├── q0 │ │ └── demo29.go │ └── q3 │ │ └── demo30.go │ ├── article22 │ ├── q0 │ │ └── demo58.go │ ├── q2 │ │ └── demo60.go │ └── q1 │ │ └── demo59.go │ ├── article27 │ └── q0 │ │ └── demo70.go │ ├── article33 │ ├── q3 │ │ └── demo86.go │ ├── q1 │ │ └── demo84.go │ └── q2 │ │ └── demo85.go │ ├── article24 │ ├── q1 │ │ └── demo63.go │ └── q2 │ │ └── demo64.go │ └── article28 │ ├── q0 │ └── demo71.go │ └── q2 │ └── demo72.go ├── gohackers_planet.jpeg ├── .gitignore ├── README.md └── mapping_table.md /src/puzzlers/go.mod: -------------------------------------------------------------------------------- 1 | module puzzlers 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /gohackers_planet.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hyper0x/Golang_Puzzlers/HEAD/gohackers_planet.jpeg -------------------------------------------------------------------------------- /src/puzzlers/article2/q0/demo1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | fmt.Println("Hello, world!") 7 | } 8 | -------------------------------------------------------------------------------- /src/puzzlers/article19/q0/demo47.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | s1 := []int{0, 1, 2, 3, 4} 5 | e5 := s1[5] 6 | _ = e5 7 | } 8 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q1/demo4_lib.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func hello(name string) { 6 | fmt.Printf("Hello, %s!\n", name) 7 | } 8 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q2/lib/demo5_lib.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import "fmt" 4 | 5 | func Hello(name string) { 6 | fmt.Printf("Hello, %s!\n", name) 7 | } 8 | -------------------------------------------------------------------------------- /src/puzzlers/article16/q1/demo38.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | for i := 0; i < 10; i++ { 7 | go func() { 8 | fmt.Println(i) 9 | }() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q3/demo54_test.go: -------------------------------------------------------------------------------- 1 | package q3 2 | 3 | import "testing" 4 | 5 | func BenchmarkGetPrimes(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | GetPrimes(1000) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q4/lib/demo6_lib.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "os" 5 | in "puzzlers/article3/q4/lib/internal" 6 | ) 7 | 8 | func Hello(name string) { 9 | in.Hello(os.Stdout, name) 10 | } 11 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q4/lib/internal/internal.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | func Hello(w io.Writer, name string) { 9 | fmt.Fprintf(w, "Hello, %s!\n", name) 10 | } 11 | -------------------------------------------------------------------------------- /src/puzzlers/article29/q2/demo74.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | str := "Go爱好者" 7 | for i, c := range str { 8 | fmt.Printf("%d: %q [% x]\n", i, c, []byte(string(c))) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q5/usage1/demo100.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | _ "net/http/pprof" 7 | ) 8 | 9 | func main() { 10 | log.Println(http.ListenAndServe("localhost:8082", nil)) 11 | } 12 | -------------------------------------------------------------------------------- /src/puzzlers/article19/q4/demo51.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | defer fmt.Println("first defer") 7 | for i := 0; i < 3; i++ { 8 | defer fmt.Printf("defer in for [%d]\n", i) 9 | } 10 | defer fmt.Println("last defer") 11 | } 12 | -------------------------------------------------------------------------------- /src/puzzlers/article5/q2/demo11.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var container = []string{"zero", "one", "two"} 6 | 7 | func main() { 8 | container := map[int]string{0: "zero", 1: "one", 2: "two"} 9 | fmt.Printf("The element is %q.\n", container[1]) 10 | } 11 | -------------------------------------------------------------------------------- /src/puzzlers/article10/q0/demo20.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch1 := make(chan int, 3) 7 | ch1 <- 2 8 | ch1 <- 1 9 | ch1 <- 3 10 | elem1 := <-ch1 11 | fmt.Printf("The first element received from channel ch1: %v\n", 12 | elem1) 13 | } 14 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q1/demo4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | ) 6 | 7 | var name string 8 | 9 | func init() { 10 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 11 | } 12 | 13 | func main() { 14 | flag.Parse() 15 | hello(name) 16 | } 17 | -------------------------------------------------------------------------------- /src/puzzlers/article5/q1/demo10.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var block = "package" 6 | 7 | func main() { 8 | block := "function" 9 | { 10 | block := "inner" 11 | fmt.Printf("The block is %s.\n", block) 12 | } 13 | fmt.Printf("The block is %s.\n", block) 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | pkg/ 9 | 10 | # Test binary, build with `go test -c` 11 | *.test 12 | 13 | # Output of the go coverage tool, specifically when used with LiteIDE 14 | *.out 15 | 16 | # IDE 17 | .idea/ 18 | .vscode/ 19 | -------------------------------------------------------------------------------- /src/puzzlers/article2/q1/demo2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | var name string 9 | 10 | func init() { 11 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 12 | } 13 | 14 | func main() { 15 | flag.Parse() 16 | fmt.Printf("Hello, %s!\n", name) 17 | } 18 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q2/demo5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "puzzlers/article3/q2/lib" 6 | ) 7 | 8 | var name string 9 | 10 | func init() { 11 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 12 | } 13 | 14 | func main() { 15 | flag.Parse() 16 | lib.Hello(name) 17 | } 18 | -------------------------------------------------------------------------------- /src/puzzlers/article12/q0/demo26.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Printer func(contents string) (n int, err error) 6 | 7 | func printToStd(contents string) (bytesNum int, err error) { 8 | return fmt.Println(contents) 9 | } 10 | 11 | func main() { 12 | var p Printer 13 | p = printToStd 14 | p("something") 15 | } 16 | -------------------------------------------------------------------------------- /src/puzzlers/article29/q1/demo73.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | str := "Go爱好者" 9 | fmt.Printf("The string: %q\n", str) 10 | fmt.Printf(" => runes(char): %q\n", []rune(str)) 11 | fmt.Printf(" => runes(hex): %x\n", []rune(str)) 12 | fmt.Printf(" => bytes(hex): [% x]\n", []byte(str)) 13 | } 14 | -------------------------------------------------------------------------------- /src/puzzlers/article4/q3/demo9.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | var err error 11 | n, err := io.WriteString(os.Stdout, "Hello, everyone!\n") // 这里对`err`进行了重声明。 12 | if err != nil { 13 | fmt.Printf("Error: %v\n", err) 14 | } 15 | fmt.Printf("%d byte(s) were written.\n", n) 16 | } 17 | -------------------------------------------------------------------------------- /src/puzzlers/article37/common/op/cpu.go: -------------------------------------------------------------------------------- 1 | package op 2 | 3 | import ( 4 | "bytes" 5 | "math/rand" 6 | "strconv" 7 | ) 8 | 9 | func CPUProfile() error { 10 | max := 10000000 11 | var buf bytes.Buffer 12 | for j := 0; j < max; j++ { 13 | num := rand.Int63n(int64(max)) 14 | str := strconv.FormatInt(num, 10) 15 | buf.WriteString(str) 16 | } 17 | _ = buf.String() 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q3/demo57_test.go: -------------------------------------------------------------------------------- 1 | package q3 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func BenchmarkGetPrimes(b *testing.B) { 9 | // 你可以注释或者还原下面这四行代码中的第一行和第四行, 10 | // 并观察测试结果的不同。 11 | b.StopTimer() 12 | time.Sleep(time.Millisecond * 500) // 模拟某个耗时但与被测程序关系不大的操作。 13 | max := 10000 14 | b.StartTimer() 15 | 16 | for i := 0; i < b.N; i++ { 17 | GetPrimes(max) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/puzzlers/article3/q4/demo6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "puzzlers/article3/q4/lib" 6 | //in "puzzlers/article3/q4/lib/internal" // 此行无法通过编译。 7 | //"os" 8 | ) 9 | 10 | var name string 11 | 12 | func init() { 13 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 14 | } 15 | 16 | func main() { 17 | flag.Parse() 18 | lib.Hello(name) 19 | //in.Hello(os.Stdout, name) 20 | } 21 | -------------------------------------------------------------------------------- /src/puzzlers/article10/q2/demo21.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // 示例1。 5 | ch1 := make(chan int, 1) 6 | ch1 <- 1 7 | //ch1 <- 2 // 通道已满,因此这里会造成阻塞。 8 | 9 | // 示例2。 10 | ch2 := make(chan int, 1) 11 | //elem, ok := <-ch2 // 通道已空,因此这里会造成阻塞。 12 | //_, _ = elem, ok 13 | ch2 <- 1 14 | 15 | // 示例3。 16 | var ch3 chan int 17 | //ch3 <- 1 // 通道的值为nil,因此这里会造成永久的阻塞! 18 | //<-ch3 // 通道的值为nil,因此这里会造成永久的阻塞! 19 | _ = ch3 20 | } 21 | -------------------------------------------------------------------------------- /src/puzzlers/article16/q2/demo39.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | //"time" 6 | ) 7 | 8 | func main() { 9 | num := 10 10 | sign := make(chan struct{}, num) 11 | 12 | for i := 0; i < num; i++ { 13 | go func() { 14 | fmt.Println(i) 15 | sign <- struct{}{} 16 | }() 17 | } 18 | 19 | // 办法1。 20 | //time.Sleep(time.Millisecond * 500) 21 | 22 | // 办法2。 23 | for j := 0; j < num; j++ { 24 | <-sign 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/puzzlers/article19/q2/demo49.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Enter function main.") 10 | caller() 11 | fmt.Println("Exit function main.") 12 | } 13 | 14 | func caller() { 15 | fmt.Println("Enter function caller.") 16 | panic(errors.New("something wrong")) // 正例。 17 | panic(fmt.Println) // 反例。 18 | fmt.Println("Exit function caller.") 19 | } 20 | -------------------------------------------------------------------------------- /src/puzzlers/article4/q2/demo8.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | var name = getTheFlag() 10 | flag.Parse() 11 | fmt.Printf("Hello, %v!\n", *name) 12 | } 13 | 14 | func getTheFlag() *string { 15 | return flag.String("name", "everyone", "The greeting object.") 16 | } 17 | 18 | //上面函数的实现也可以是这样的。 19 | //func getTheFlag() *int { 20 | // return flag.Int("num", 1, "The number of greeting object.") 21 | //} 22 | -------------------------------------------------------------------------------- /src/puzzlers/article35/q0/demo90.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | ) 7 | 8 | func main() { 9 | fd1, err := syscall.Socket( 10 | syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) 11 | if err != nil { 12 | fmt.Printf("socket error: %v\n", err) 13 | return 14 | } 15 | defer syscall.Close(fd1) 16 | fmt.Printf("The file descriptor of socket:%d\n", fd1) 17 | 18 | // 省略若干代码。 19 | // 如果真要完全使用syscall包中的程序实体建立网络连接的话, 20 | // 过程太过繁琐而且完全没有必要。 21 | // 所以,我在这里就不做展示了。 22 | } 23 | -------------------------------------------------------------------------------- /src/puzzlers/article19/q1/demo48.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println("Enter function main.") 9 | caller1() 10 | fmt.Println("Exit function main.") 11 | } 12 | 13 | func caller1() { 14 | fmt.Println("Enter function caller1.") 15 | caller2() 16 | fmt.Println("Exit function caller1.") 17 | } 18 | 19 | func caller2() { 20 | fmt.Println("Enter function caller2.") 21 | s1 := []int{0, 1, 2, 3, 4} 22 | e5 := s1[5] 23 | _ = e5 24 | fmt.Println("Exit function caller2.") 25 | } 26 | -------------------------------------------------------------------------------- /src/puzzlers/article9/q3/demo19.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var m map[string]int 7 | 8 | key := "two" 9 | elem, ok := m["two"] 10 | fmt.Printf("The element paired with key %q in nil map: %d (%v)\n", 11 | key, elem, ok) 12 | 13 | fmt.Printf("The length of nil map: %d\n", 14 | len(m)) 15 | 16 | fmt.Printf("Delete the key-element pair by key %q...\n", 17 | key) 18 | delete(m, key) 19 | 20 | elem = 2 21 | fmt.Println("Add a key-element pair to a nil map...") 22 | m["two"] = elem // 这里会引发panic。 23 | } 24 | -------------------------------------------------------------------------------- /src/puzzlers/article15/q2/demo36.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Dog struct { 4 | name string 5 | } 6 | 7 | func New(name string) Dog { 8 | return Dog{name} 9 | } 10 | 11 | func (dog *Dog) SetName(name string) { 12 | dog.name = name 13 | } 14 | 15 | func (dog Dog) Name() string { 16 | return dog.name 17 | } 18 | 19 | func main() { 20 | // 示例1。 21 | //New("little pig").SetName("monster") // 不能调用不可寻址的值的指针方法。 22 | 23 | // 示例2。 24 | map[string]int{"the": 0, "word": 0, "counter": 0}["word"]++ 25 | map1 := map[string]int{"the": 0, "word": 0, "counter": 0} 26 | map1["word"]++ 27 | } 28 | -------------------------------------------------------------------------------- /src/puzzlers/article7/q3/demo17.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | a1 := [7]int{1, 2, 3, 4, 5, 6, 7} 8 | fmt.Printf("a1: %v (len: %d, cap: %d)\n", 9 | a1, len(a1), cap(a1)) 10 | s9 := a1[1:4] 11 | //s9[0] = 1 12 | fmt.Printf("s9: %v (len: %d, cap: %d)\n", 13 | s9, len(s9), cap(s9)) 14 | for i := 1; i <= 5; i++ { 15 | s9 = append(s9, i) 16 | fmt.Printf("s9(%d): %v (len: %d, cap: %d)\n", 17 | i, s9, len(s9), cap(s9)) 18 | } 19 | fmt.Printf("a1: %v (len: %d, cap: %d)\n", 20 | a1, len(a1), cap(a1)) 21 | fmt.Println() 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/puzzlers/article10/q3/demo22.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch1 := make(chan int, 2) 7 | // 发送方。 8 | go func() { 9 | for i := 0; i < 10; i++ { 10 | fmt.Printf("Sender: sending element %v...\n", i) 11 | ch1 <- i 12 | } 13 | fmt.Println("Sender: close the channel...") 14 | close(ch1) 15 | }() 16 | 17 | // 接收方。 18 | for { 19 | elem, ok := <-ch1 20 | if !ok { 21 | fmt.Println("Receiver: closed channel") 22 | break 23 | } 24 | fmt.Printf("Receiver: received an element: %v\n", elem) 25 | } 26 | 27 | fmt.Println("End.") 28 | } 29 | -------------------------------------------------------------------------------- /src/puzzlers/article16/q3/demo40.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync/atomic" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | var count uint32 11 | trigger := func(i uint32, fn func()) { 12 | for { 13 | if n := atomic.LoadUint32(&count); n == i { 14 | fn() 15 | atomic.AddUint32(&count, 1) 16 | break 17 | } 18 | time.Sleep(time.Nanosecond) 19 | } 20 | } 21 | for i := uint32(0); i < 10; i++ { 22 | go func(i uint32) { 23 | fn := func() { 24 | fmt.Println(i) 25 | } 26 | trigger(i, fn) 27 | }(i) 28 | } 29 | trigger(10, func() {}) 30 | } 31 | -------------------------------------------------------------------------------- /src/puzzlers/article4/q1/demo7.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | var name string // [1] 10 | flag.StringVar(&name, "name", "everyone", "The greeting object.") // [2] 11 | 12 | // 方式1。 13 | //var name = flag.String("name", "everyone", "The greeting object.") 14 | 15 | // 方式2。 16 | //name := flag.String("name", "everyone", "The greeting object.") 17 | 18 | flag.Parse() 19 | fmt.Printf("Hello, %v!\n", name) 20 | 21 | // 适用于方式1和方式2。 22 | //fmt.Printf("Hello, %v!\n", *name) 23 | } 24 | -------------------------------------------------------------------------------- /src/puzzlers/article17/q2/demo42.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | //value1 := [...]int8{0, 1, 2, 3, 4, 5, 6} 8 | //switch 1 + 3 { // 这条语句无法编译通过。 9 | //case value1[0], value1[1]: 10 | // fmt.Println("0 or 1") 11 | //case value1[2], value1[3]: 12 | // fmt.Println("2 or 3") 13 | //case value1[4], value1[5], value1[6]: 14 | // fmt.Println("4 or 5 or 6") 15 | //} 16 | 17 | // 示例2。 18 | value2 := [...]int8{0, 1, 2, 3, 4, 5, 6} 19 | switch value2[4] { 20 | case 0, 1: 21 | fmt.Println("0 or 1") 22 | case 2, 3: 23 | fmt.Println("2 or 3") 24 | case 4, 5, 6: 25 | fmt.Println("4 or 5 or 6") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/puzzlers/article19/q3/demo50.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("Enter function main.") 10 | 11 | defer func() { 12 | fmt.Println("Enter defer function.") 13 | 14 | // recover函数的正确用法。 15 | if p := recover(); p != nil { 16 | fmt.Printf("panic: %s\n", p) 17 | } 18 | 19 | fmt.Println("Exit defer function.") 20 | }() 21 | 22 | // recover函数的错误用法。 23 | fmt.Printf("no panic: %v\n", recover()) 24 | 25 | // 引发panic。 26 | panic(errors.New("something wrong")) 27 | 28 | // recover函数的错误用法。 29 | p := recover() 30 | fmt.Printf("panic: %s\n", p) 31 | 32 | fmt.Println("Exit function main.") 33 | } 34 | -------------------------------------------------------------------------------- /src/puzzlers/article31/q0/demo78.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | // 示例1。 10 | var buffer1 bytes.Buffer 11 | contents := "Simple byte buffer for marshaling data." 12 | fmt.Printf("Write contents %q ...\n", contents) 13 | buffer1.WriteString(contents) 14 | fmt.Printf("The length of buffer: %d\n", buffer1.Len()) 15 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 16 | fmt.Println() 17 | 18 | // 示例2。 19 | p1 := make([]byte, 7) 20 | n, _ := buffer1.Read(p1) 21 | fmt.Printf("%d bytes were read. (call Read)\n", n) 22 | fmt.Printf("The length of buffer: %d\n", buffer1.Len()) 23 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 24 | } 25 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q0/demo52.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | ) 8 | 9 | var name string 10 | 11 | func init() { 12 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 13 | } 14 | 15 | func main() { 16 | flag.Parse() 17 | greeting, err := hello(name) 18 | if err != nil { 19 | fmt.Printf("error: %s\n", err) 20 | return 21 | } 22 | fmt.Println(greeting, introduce()) 23 | } 24 | 25 | // hello 用于生成问候内容。 26 | func hello(name string) (string, error) { 27 | if name == "" { 28 | return "", errors.New("empty name") 29 | } 30 | return fmt.Sprintf("Hello, %s!", name), nil 31 | } 32 | 33 | // introduce 用于生成介绍内容。 34 | func introduce() string { 35 | return "Welcome to my Golang column." 36 | } 37 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q2/demo53.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | ) 8 | 9 | var name string 10 | 11 | func init() { 12 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 13 | } 14 | 15 | func main() { 16 | flag.Parse() 17 | greeting, err := hello(name) 18 | if err != nil { 19 | fmt.Printf("error: %s\n", err) 20 | return 21 | } 22 | fmt.Println(greeting, introduce()) 23 | } 24 | 25 | // hello 用于生成问候内容。 26 | func hello(name string) (string, error) { 27 | if name == "" { 28 | return "", errors.New("empty name") 29 | } 30 | return fmt.Sprintf("Hello, %s!", name), nil 31 | } 32 | 33 | // introduce 用于生成介绍内容。 34 | func introduce() string { 35 | return "Welcome to my Golang column." 36 | } 37 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q3/demo54.go: -------------------------------------------------------------------------------- 1 | package q3 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // GetPrimes 用于获取小于或等于参数max的所有质数。 8 | // 本函数使用的是爱拉托逊斯筛选法(Sieve Of Eratosthenes)。 9 | func GetPrimes(max int) []int { 10 | if max <= 1 { 11 | return []int{} 12 | } 13 | marks := make([]bool, max) 14 | var count int 15 | squareRoot := int(math.Sqrt(float64(max))) 16 | for i := 2; i <= squareRoot; i++ { 17 | if marks[i] == false { 18 | for j := i * i; j < max; j += i { 19 | if marks[j] == false { 20 | marks[j] = true 21 | count++ 22 | } 23 | } 24 | } 25 | } 26 | primes := make([]int, 0, max-count) 27 | for i := 2; i < max; i++ { 28 | if marks[i] == false { 29 | primes = append(primes, i) 30 | } 31 | } 32 | return primes 33 | } 34 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q1/demo55.go: -------------------------------------------------------------------------------- 1 | package q1 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // GetPrimes 用于获取小于或等于参数max的所有质数。 8 | // 本函数使用的是爱拉托逊斯筛选法(Sieve Of Eratosthenes)。 9 | func GetPrimes(max int) []int { 10 | if max <= 1 { 11 | return []int{} 12 | } 13 | marks := make([]bool, max) 14 | var count int 15 | squareRoot := int(math.Sqrt(float64(max))) 16 | for i := 2; i <= squareRoot; i++ { 17 | if marks[i] == false { 18 | for j := i * i; j < max; j += i { 19 | if marks[j] == false { 20 | marks[j] = true 21 | count++ 22 | } 23 | } 24 | } 25 | } 26 | primes := make([]int, 0, max-count) 27 | for i := 2; i < max; i++ { 28 | if marks[i] == false { 29 | primes = append(primes, i) 30 | } 31 | } 32 | return primes 33 | } 34 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q2/demo56.go: -------------------------------------------------------------------------------- 1 | package q2 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // GetPrimes 用于获取小于或等于参数max的所有质数。 8 | // 本函数使用的是爱拉托逊斯筛选法(Sieve Of Eratosthenes)。 9 | func GetPrimes(max int) []int { 10 | if max <= 1 { 11 | return []int{} 12 | } 13 | marks := make([]bool, max) 14 | var count int 15 | squareRoot := int(math.Sqrt(float64(max))) 16 | for i := 2; i <= squareRoot; i++ { 17 | if marks[i] == false { 18 | for j := i * i; j < max; j += i { 19 | if marks[j] == false { 20 | marks[j] = true 21 | count++ 22 | } 23 | } 24 | } 25 | } 26 | primes := make([]int, 0, max-count) 27 | for i := 2; i < max; i++ { 28 | if marks[i] == false { 29 | primes = append(primes, i) 30 | } 31 | } 32 | return primes 33 | } 34 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q3/demo57.go: -------------------------------------------------------------------------------- 1 | package q3 2 | 3 | import ( 4 | "math" 5 | ) 6 | 7 | // GetPrimes 用于获取小于或等于参数max的所有质数。 8 | // 本函数使用的是爱拉托逊斯筛选法(Sieve Of Eratosthenes)。 9 | func GetPrimes(max int) []int { 10 | if max <= 1 { 11 | return []int{} 12 | } 13 | marks := make([]bool, max) 14 | var count int 15 | squareRoot := int(math.Sqrt(float64(max))) 16 | for i := 2; i <= squareRoot; i++ { 17 | if marks[i] == false { 18 | for j := i * i; j < max; j += i { 19 | if marks[j] == false { 20 | marks[j] = true 21 | count++ 22 | } 23 | } 24 | } 25 | } 26 | primes := make([]int, 0, max-count) 27 | for i := 2; i < max; i++ { 28 | if marks[i] == false { 29 | primes = append(primes, i) 30 | } 31 | } 32 | return primes 33 | } 34 | -------------------------------------------------------------------------------- /src/puzzlers/article11/q3/demo25.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var channels = [3]chan int{ 6 | nil, 7 | make(chan int), 8 | nil, 9 | } 10 | 11 | var numbers = []int{1, 2, 3} 12 | 13 | func main() { 14 | select { 15 | case getChan(0) <- getNumber(0): 16 | fmt.Println("The first candidate case is selected.") 17 | case getChan(1) <- getNumber(1): 18 | fmt.Println("The second candidate case is selected.") 19 | case getChan(2) <- getNumber(2): 20 | fmt.Println("The third candidate case is selected") 21 | default: 22 | fmt.Println("No candidate case is selected!") 23 | } 24 | } 25 | 26 | func getNumber(i int) int { 27 | fmt.Printf("numbers[%d]\n", i) 28 | return numbers[i] 29 | } 30 | 31 | func getChan(i int) chan int { 32 | fmt.Printf("channels[%d]\n", i) 33 | return channels[i] 34 | } 35 | -------------------------------------------------------------------------------- /src/puzzlers/article30/q2/demo76.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func main() { 8 | // 示例1。 9 | var builder1 strings.Builder 10 | builder1.Grow(1) 11 | 12 | f1 := func(b strings.Builder) { 13 | //b.Grow(1) // 这里会引发panic。 14 | } 15 | f1(builder1) 16 | 17 | ch1 := make(chan strings.Builder, 1) 18 | ch1 <- builder1 19 | builder2 := <-ch1 20 | //builder2.Grow(1) // 这里会引发panic。 21 | _ = builder2 22 | 23 | builder3 := builder1 24 | //builder3.Grow(1) // 这里会引发panic。 25 | _ = builder3 26 | 27 | // 示例2。 28 | f2 := func(bp *strings.Builder) { 29 | (*bp).Grow(1) // 这里虽然不会引发panic,但不是并发安全的。 30 | builder4 := *bp 31 | //builder4.Grow(1) // 这里会引发panic。 32 | _ = builder4 33 | } 34 | f2(&builder1) 35 | 36 | builder1.Reset() 37 | builder5 := builder1 38 | builder5.Grow(1) // 这里不会引发panic。 39 | } 40 | -------------------------------------------------------------------------------- /src/puzzlers/article17/q1/demo41.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | numbers1 := []int{1, 2, 3, 4, 5, 6} 8 | for i := range numbers1 { 9 | if i == 3 { 10 | numbers1[i] |= i 11 | } 12 | } 13 | fmt.Println(numbers1) 14 | fmt.Println() 15 | 16 | // 示例2。 17 | numbers2 := [...]int{1, 2, 3, 4, 5, 6} 18 | maxIndex2 := len(numbers2) - 1 19 | for i, e := range numbers2 { 20 | if i == maxIndex2 { 21 | numbers2[0] += e 22 | } else { 23 | numbers2[i+1] += e 24 | } 25 | } 26 | fmt.Println(numbers2) 27 | fmt.Println() 28 | 29 | // 示例3。 30 | numbers3 := []int{1, 2, 3, 4, 5, 6} 31 | maxIndex3 := len(numbers2) - 1 32 | for i, e := range numbers3 { 33 | if i == maxIndex3 { 34 | numbers3[0] += e 35 | } else { 36 | numbers3[i+1] += e 37 | } 38 | } 39 | fmt.Println(numbers3) 40 | } 41 | -------------------------------------------------------------------------------- /src/puzzlers/article14/q0/demo31.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Pet interface { 6 | SetName(name string) 7 | Name() string 8 | Category() string 9 | } 10 | 11 | type Dog struct { 12 | name string // 名字。 13 | } 14 | 15 | func (dog *Dog) SetName(name string) { 16 | dog.name = name 17 | } 18 | 19 | func (dog Dog) Name() string { 20 | return dog.name 21 | } 22 | 23 | func (dog Dog) Category() string { 24 | return "dog" 25 | } 26 | 27 | func main() { 28 | // 示例1。 29 | dog := Dog{"little pig"} 30 | _, ok := interface{}(dog).(Pet) 31 | fmt.Printf("Dog implements interface Pet: %v\n", ok) 32 | _, ok = interface{}(&dog).(Pet) 33 | fmt.Printf("*Dog implements interface Pet: %v\n", ok) 34 | fmt.Println() 35 | 36 | // 示例2。 37 | var pet Pet = &dog 38 | fmt.Printf("This pet is a %s, the name is %q.\n", 39 | pet.Category(), pet.Name()) 40 | } 41 | -------------------------------------------------------------------------------- /src/puzzlers/article2/q3/demo3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | var name string 10 | 11 | // 方式3。 12 | //var cmdLine = flag.NewFlagSet("question", flag.ExitOnError) 13 | 14 | func init() { 15 | // 方式2。 16 | flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError) 17 | flag.CommandLine.Usage = func() { 18 | fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") 19 | flag.PrintDefaults() 20 | } 21 | // 方式3。 22 | //cmdLine.StringVar(&name, "name", "everyone", "The greeting object.") 23 | flag.StringVar(&name, "name", "everyone", "The greeting object.") 24 | } 25 | 26 | func main() { 27 | // 方式1。 28 | //flag.Usage = func() { 29 | // fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question") 30 | // flag.PrintDefaults() 31 | //} 32 | // 方式3。 33 | //cmdLine.Parse(os.Args[1:]) 34 | flag.Parse() 35 | fmt.Printf("Hello, %s!\n", name) 36 | } 37 | -------------------------------------------------------------------------------- /src/puzzlers/article18/q0/demo44.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func echo(request string) (response string, err error) { 9 | if request == "" { 10 | err = errors.New("empty request") 11 | return 12 | } 13 | response = fmt.Sprintf("echo: %s", request) 14 | return 15 | } 16 | 17 | func main() { 18 | // 示例1。 19 | for _, req := range []string{"", "hello!"} { 20 | fmt.Printf("request: %s\n", req) 21 | resp, err := echo(req) 22 | if err != nil { 23 | fmt.Printf("error: %s\n", err) 24 | continue 25 | } 26 | fmt.Printf("response: %s\n", resp) 27 | } 28 | fmt.Println() 29 | 30 | // 示例2。 31 | err1 := fmt.Errorf("invalid contents: %s", "#$%") 32 | err2 := errors.New(fmt.Sprintf("invalid contents: %s", "#$%")) 33 | if err1.Error() == err2.Error() { 34 | fmt.Println("The error messages in err1 and err2 are the same.") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/puzzlers/article9/q1/demo18.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | // 示例1。 5 | //var badMap1 = map[[]int]int{} // 这里会引发编译错误。 6 | //_ = badMap1 7 | 8 | // 示例2。 9 | //var badMap2 = map[interface{}]int{ 10 | // "1": 1, 11 | // []int{2}: 2, // 这里会引发panic。 12 | // 3: 3, 13 | //} 14 | //_ = badMap2 15 | 16 | // 示例3。 17 | //var badMap3 map[[1][]string]int // 这里会引发编译错误。 18 | //_ = badMap3 19 | 20 | // 示例4。 21 | //type BadKey1 struct { 22 | // slice []string 23 | //} 24 | //var badMap4 map[BadKey1]int // 这里会引发编译错误。 25 | //_ = badMap4 26 | 27 | // 示例5。 28 | //var badMap5 map[[1][2][3][]string]int // 这里会引发编译错误。 29 | //_ = badMap5 30 | 31 | // 示例6。 32 | //type BadKey2Field1 struct { 33 | // slice []string 34 | //} 35 | //type BadKey2 struct { 36 | // field BadKey2Field1 37 | //} 38 | //var badMap6 map[BadKey2]int // 这里会引发编译错误。 39 | //_ = badMap6 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/puzzlers/article7/q1/demo15.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | s1 := make([]int, 5) 8 | fmt.Printf("The length of s1: %d\n", len(s1)) 9 | fmt.Printf("The capacity of s1: %d\n", cap(s1)) 10 | fmt.Printf("The value of s1: %d\n", s1) 11 | s2 := make([]int, 5, 8) 12 | fmt.Printf("The length of s2: %d\n", len(s2)) 13 | fmt.Printf("The capacity of s2: %d\n", cap(s2)) 14 | fmt.Printf("The value of s2: %d\n", s2) 15 | fmt.Println() 16 | 17 | // 示例2。 18 | s3 := []int{1, 2, 3, 4, 5, 6, 7, 8} 19 | s4 := s3[3:6] 20 | fmt.Printf("The length of s4: %d\n", len(s4)) 21 | fmt.Printf("The capacity of s4: %d\n", cap(s4)) 22 | fmt.Printf("The value of s4: %d\n", s4) 23 | fmt.Println() 24 | 25 | // 示例3。 26 | s5 := s4[:cap(s4)] 27 | fmt.Printf("The length of s5: %d\n", len(s5)) 28 | fmt.Printf("The capacity of s5: %d\n", cap(s5)) 29 | fmt.Printf("The value of s5: %d\n", s5) 30 | } 31 | -------------------------------------------------------------------------------- /src/puzzlers/article15/q3/demo37.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | type Dog struct { 9 | name string 10 | } 11 | 12 | func (dog *Dog) SetName(name string) { 13 | dog.name = name 14 | } 15 | 16 | func (dog Dog) Name() string { 17 | return dog.name 18 | } 19 | 20 | func main() { 21 | // 示例1。 22 | dog := Dog{"little pig"} 23 | dogP := &dog 24 | dogPtr := uintptr(unsafe.Pointer(dogP)) 25 | 26 | namePtr := dogPtr + unsafe.Offsetof(dogP.name) 27 | nameP := (*string)(unsafe.Pointer(namePtr)) 28 | fmt.Printf("nameP == &(dogP.name)? %v\n", 29 | nameP == &(dogP.name)) 30 | fmt.Printf("The name of dog is %q.\n", *nameP) 31 | 32 | *nameP = "monster" 33 | fmt.Printf("The name of dog is %q.\n", dogP.name) 34 | fmt.Println() 35 | 36 | // 示例2。 37 | // 下面这种不匹配的转换虽然不会引发panic,但是其结果往往不符合预期。 38 | numP := (*int)(unsafe.Pointer(namePtr)) 39 | num := *numP 40 | fmt.Printf("This is an unexpected number: %d\n", num) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q1/demo96.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "puzzlers/article37/common" 8 | "puzzlers/article37/common/op" 9 | "runtime/pprof" 10 | ) 11 | 12 | var ( 13 | profileName = "cpuprofile.out" 14 | ) 15 | 16 | func main() { 17 | f, err := common.CreateFile("", profileName) 18 | if err != nil { 19 | fmt.Printf("CPU profile creation error: %v\n", err) 20 | return 21 | } 22 | defer f.Close() 23 | if err := startCPUProfile(f); err != nil { 24 | fmt.Printf("CPU profile start error: %v\n", err) 25 | return 26 | } 27 | if err = common.Execute(op.CPUProfile, 10); err != nil { 28 | fmt.Printf("execute error: %v\n", err) 29 | return 30 | } 31 | stopCPUProfile() 32 | } 33 | 34 | func startCPUProfile(f *os.File) error { 35 | if f == nil { 36 | return errors.New("nil file") 37 | } 38 | return pprof.StartCPUProfile(f) 39 | } 40 | 41 | func stopCPUProfile() { 42 | pprof.StopCPUProfile() 43 | } 44 | -------------------------------------------------------------------------------- /src/puzzlers/article36/q0/demo93.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | host := "google.cn" 10 | 11 | // 示例1。 12 | url1 := "http://" + host 13 | fmt.Printf("Send request to %q with method GET ...\n", url1) 14 | resp1, err := http.Get(url1) 15 | if err != nil { 16 | fmt.Printf("request sending error: %v\n", err) 17 | return 18 | } 19 | defer resp1.Body.Close() 20 | line1 := resp1.Proto + " " + resp1.Status 21 | fmt.Printf("The first line of response:\n%s\n", line1) 22 | fmt.Println() 23 | 24 | // 示例2。 25 | url2 := "https://golang." + host 26 | fmt.Printf("Send request to %q with method GET ...\n", url2) 27 | var httpClient1 http.Client 28 | resp2, err := httpClient1.Get(url2) 29 | if err != nil { 30 | fmt.Printf("request sending error: %v\n", err) 31 | return 32 | } 33 | defer resp2.Body.Close() 34 | line2 := resp2.Proto + " " + resp2.Status 35 | fmt.Printf("The first line of response:\n%s\n", line2) 36 | } 37 | -------------------------------------------------------------------------------- /src/puzzlers/article37/common/op/mem.go: -------------------------------------------------------------------------------- 1 | package op 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "math/rand" 7 | ) 8 | 9 | // box 代表数据盒子。 10 | type box struct { 11 | Str string 12 | Code rune 13 | Bytes []byte 14 | } 15 | 16 | func MemProfile() error { 17 | max := 50000 18 | var buf bytes.Buffer 19 | for j := 0; j < max; j++ { 20 | seed := rand.Intn(95) + 32 21 | one := createBox(seed) 22 | b, err := genJSON(one) 23 | if err != nil { 24 | return err 25 | } 26 | buf.Write(b) 27 | buf.WriteByte('\t') 28 | } 29 | _ = buf.String() 30 | return nil 31 | } 32 | 33 | func createBox(seed int) box { 34 | if seed <= 0 { 35 | seed = 1 36 | } 37 | var array []byte 38 | size := seed * 8 39 | for i := 0; i < size; i++ { 40 | array = append(array, byte(seed)) 41 | } 42 | return box{ 43 | Str: string(seed), 44 | Code: rune(seed), 45 | Bytes: array, 46 | } 47 | } 48 | 49 | func genJSON(one box) ([]byte, error) { 50 | return json.Marshal(one) 51 | } 52 | -------------------------------------------------------------------------------- /src/puzzlers/article17/q3/demo43.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | //value3 := [...]int8{0, 1, 2, 3, 4, 5, 6} 8 | //switch value3[4] { // 这条语句无法编译通过。 9 | //case 0, 1, 2: 10 | // fmt.Println("0 or 1 or 2") 11 | //case 2, 3, 4: 12 | // fmt.Println("2 or 3 or 4") 13 | //case 4, 5, 6: 14 | // fmt.Println("4 or 5 or 6") 15 | //} 16 | 17 | // 示例2。 18 | value5 := [...]int8{0, 1, 2, 3, 4, 5, 6} 19 | switch value5[4] { 20 | case value5[0], value5[1], value5[2]: 21 | fmt.Println("0 or 1 or 2") 22 | case value5[2], value5[3], value5[4]: 23 | fmt.Println("2 or 3 or 4") 24 | case value5[4], value5[5], value5[6]: 25 | fmt.Println("4 or 5 or26") 26 | } 27 | 28 | // 示例3。 29 | //value6 := interface{}(byte(127)) 30 | //switch t := value6.(type) { // 这条语句无法编译通过。 31 | //case uint8, uint16: 32 | // fmt.Println("uint8 or uint16") 33 | //case byte: 34 | // fmt.Printf("byte") 35 | //default: 36 | // fmt.Printf("unsupported type: %T", t) 37 | //} 38 | } 39 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q2/demo97.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "puzzlers/article37/common" 8 | "puzzlers/article37/common/op" 9 | "runtime" 10 | "runtime/pprof" 11 | ) 12 | 13 | var ( 14 | profileName = "memprofile.out" 15 | memProfileRate = 8 16 | ) 17 | 18 | func main() { 19 | f, err := common.CreateFile("", profileName) 20 | if err != nil { 21 | fmt.Printf("memory profile creation error: %v\n", err) 22 | return 23 | } 24 | defer f.Close() 25 | startMemProfile() 26 | if err = common.Execute(op.MemProfile, 10); err != nil { 27 | fmt.Printf("execute error: %v\n", err) 28 | return 29 | } 30 | if err := stopMemProfile(f); err != nil { 31 | fmt.Printf("memory profile stop error: %v\n", err) 32 | return 33 | } 34 | } 35 | 36 | func startMemProfile() { 37 | runtime.MemProfileRate = memProfileRate 38 | } 39 | 40 | func stopMemProfile(f *os.File) error { 41 | if f == nil { 42 | return errors.New("nil file") 43 | } 44 | return pprof.WriteHeapProfile(f) 45 | } 46 | -------------------------------------------------------------------------------- /src/puzzlers/article30/q1/demo75.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | // 示例1。 10 | var builder1 strings.Builder 11 | builder1.WriteString("A Builder is used to efficiently build a string using Write methods.") 12 | fmt.Printf("The first output(%d):\n%q\n", builder1.Len(), builder1.String()) 13 | fmt.Println() 14 | builder1.WriteByte(' ') 15 | builder1.WriteString("It minimizes memory copying. The zero value is ready to use.") 16 | builder1.Write([]byte{'\n', '\n'}) 17 | builder1.WriteString("Do not copy a non-zero Builder.") 18 | fmt.Printf("The second output(%d):\n\"%s\"\n", builder1.Len(), builder1.String()) 19 | fmt.Println() 20 | 21 | // 示例2。 22 | fmt.Println("Grow the builder ...") 23 | builder1.Grow(10) 24 | fmt.Printf("The length of contents in the builder is %d.\n", builder1.Len()) 25 | fmt.Println() 26 | 27 | // 示例3。 28 | fmt.Println("Reset the builder ...") 29 | builder1.Reset() 30 | fmt.Printf("The third output(%d):\n%q\n", builder1.Len(), builder1.String()) 31 | } 32 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q5/usage2/demo101.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/pprof" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | mux := http.NewServeMux() 12 | pathPrefix := "/d/pprof/" 13 | mux.HandleFunc(pathPrefix, 14 | func(w http.ResponseWriter, r *http.Request) { 15 | name := strings.TrimPrefix(r.URL.Path, pathPrefix) 16 | if name != "" { 17 | pprof.Handler(name).ServeHTTP(w, r) 18 | return 19 | } 20 | pprof.Index(w, r) 21 | }) 22 | mux.HandleFunc(pathPrefix+"cmdline", pprof.Cmdline) 23 | mux.HandleFunc(pathPrefix+"profile", pprof.Profile) 24 | mux.HandleFunc(pathPrefix+"symbol", pprof.Symbol) 25 | mux.HandleFunc(pathPrefix+"trace", pprof.Trace) 26 | 27 | server := http.Server{ 28 | Addr: "localhost:8083", 29 | Handler: mux, 30 | } 31 | 32 | if err := server.ListenAndServe(); err != nil { 33 | if err == http.ErrServerClosed { 34 | log.Println("HTTP server closed.") 35 | } else { 36 | log.Printf("HTTP server error: %v\n", err) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q3/demo98.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "puzzlers/article37/common" 8 | "puzzlers/article37/common/op" 9 | "runtime" 10 | "runtime/pprof" 11 | ) 12 | 13 | var ( 14 | profileName = "blockprofile.out" 15 | blockProfileRate = 2 16 | debug = 0 17 | ) 18 | 19 | func main() { 20 | f, err := common.CreateFile("", profileName) 21 | if err != nil { 22 | fmt.Printf("block profile creation error: %v\n", err) 23 | return 24 | } 25 | defer f.Close() 26 | startBlockProfile() 27 | if err = common.Execute(op.BlockProfile, 10); err != nil { 28 | fmt.Printf("execute error: %v\n", err) 29 | return 30 | } 31 | if err := stopBlockProfile(f); err != nil { 32 | fmt.Printf("block profile stop error: %v\n", err) 33 | return 34 | } 35 | } 36 | 37 | func startBlockProfile() { 38 | runtime.SetBlockProfileRate(blockProfileRate) 39 | } 40 | 41 | func stopBlockProfile(f *os.File) error { 42 | if f == nil { 43 | return errors.New("nil file") 44 | } 45 | return pprof.Lookup("block").WriteTo(f, debug) 46 | } 47 | -------------------------------------------------------------------------------- /src/puzzlers/article11/q1/demo23.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | ) 7 | 8 | func main() { 9 | // 示例1。 10 | // 只能发不能收的通道。 11 | var uselessChan = make(chan<- int, 1) 12 | // 只能收不能发的通道。 13 | var anotherUselessChan = make(<-chan int, 1) 14 | // 这里打印的是可以分别代表两个通道的指针的16进制表示。 15 | fmt.Printf("The useless channels: %v, %v\n", 16 | uselessChan, anotherUselessChan) 17 | 18 | // 示例2。 19 | intChan1 := make(chan int, 3) 20 | SendInt(intChan1) 21 | 22 | // 示例4。 23 | intChan2 := getIntChan() 24 | for elem := range intChan2 { 25 | fmt.Printf("The element in intChan2: %v\n", elem) 26 | } 27 | 28 | // 示例5。 29 | _ = GetIntChan(getIntChan) 30 | } 31 | 32 | // 示例2。 33 | func SendInt(ch chan<- int) { 34 | ch <- rand.Intn(1000) 35 | } 36 | 37 | // 示例3。 38 | type Notifier interface { 39 | SendInt(ch chan<- int) 40 | } 41 | 42 | // 示例4。 43 | func getIntChan() <-chan int { 44 | num := 5 45 | ch := make(chan int, num) 46 | for i := 0; i < num; i++ { 47 | ch <- i 48 | } 49 | close(ch) 50 | return ch 51 | } 52 | 53 | // 示例5。 54 | type GetIntChan func() <-chan int 55 | -------------------------------------------------------------------------------- /src/puzzlers/article37/common/op/block.go: -------------------------------------------------------------------------------- 1 | package op 2 | 3 | import ( 4 | "math/rand" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func BlockProfile() error { 10 | max := 100 11 | senderNum := max / 2 12 | receiverNum := max / 4 13 | ch1 := make(chan int, max/4) 14 | 15 | var senderGroup sync.WaitGroup 16 | senderGroup.Add(senderNum) 17 | repeat := 50000 18 | for j := 0; j < senderNum; j++ { 19 | go send(ch1, &senderGroup, repeat) 20 | } 21 | 22 | go func() { 23 | senderGroup.Wait() 24 | close(ch1) 25 | }() 26 | 27 | var receiverGroup sync.WaitGroup 28 | receiverGroup.Add(receiverNum) 29 | for j := 0; j < receiverNum; j++ { 30 | go receive(ch1, &receiverGroup) 31 | } 32 | receiverGroup.Wait() 33 | return nil 34 | } 35 | 36 | func send(ch1 chan int, wg *sync.WaitGroup, repeat int) { 37 | defer wg.Done() 38 | time.Sleep(time.Millisecond * 10) 39 | for k := 0; k < repeat; k++ { 40 | elem := rand.Intn(repeat) 41 | ch1 <- elem 42 | } 43 | } 44 | 45 | func receive(ch1 chan int, wg *sync.WaitGroup) { 46 | defer wg.Done() 47 | for elem := range ch1 { 48 | _ = elem 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/puzzlers/article6/q1/demo12.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var container = []string{"zero", "one", "two"} 8 | 9 | func main() { 10 | container := map[int]string{0: "zero", 1: "one", 2: "two"} 11 | 12 | // 方式1。 13 | _, ok1 := interface{}(container).([]string) 14 | _, ok2 := interface{}(container).(map[int]string) 15 | if !(ok1 || ok2) { 16 | fmt.Printf("Error: unsupported container type: %T\n", container) 17 | return 18 | } 19 | fmt.Printf("The element is %q. (container type: %T)\n", 20 | container[1], container) 21 | 22 | // 方式2。 23 | elem, err := getElement(container) 24 | if err != nil { 25 | fmt.Printf("Error: %s\n", err) 26 | return 27 | } 28 | fmt.Printf("The element is %q. (container type: %T)\n", 29 | elem, container) 30 | } 31 | 32 | func getElement(containerI interface{}) (elem string, err error) { 33 | switch t := containerI.(type) { 34 | case []string: 35 | elem = t[1] 36 | case map[int]string: 37 | elem = t[1] 38 | default: 39 | err = fmt.Errorf("unsupported container type: %T", containerI) 40 | return 41 | } 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /src/puzzlers/article12/q1/demo27.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | type operate func(x, y int) int 9 | 10 | // 方案1。 11 | func calculate(x int, y int, op operate) (int, error) { 12 | if op == nil { 13 | return 0, errors.New("invalid operation") 14 | } 15 | return op(x, y), nil 16 | } 17 | 18 | // 方案2。 19 | type calculateFunc func(x int, y int) (int, error) 20 | 21 | func genCalculator(op operate) calculateFunc { 22 | return func(x int, y int) (int, error) { 23 | if op == nil { 24 | return 0, errors.New("invalid operation") 25 | } 26 | return op(x, y), nil 27 | } 28 | } 29 | 30 | func main() { 31 | // 方案1。 32 | x, y := 12, 23 33 | op := func(x, y int) int { 34 | return x + y 35 | } 36 | result, err := calculate(x, y, op) 37 | fmt.Printf("The result: %d (error: %v)\n", 38 | result, err) 39 | result, err = calculate(x, y, nil) 40 | fmt.Printf("The result: %d (error: %v)\n", 41 | result, err) 42 | 43 | // 方案2。 44 | x, y = 56, 78 45 | add := genCalculator(op) 46 | result, err = add(x, y) 47 | fmt.Printf("The result: %d (error: %v)\n", 48 | result, err) 49 | } 50 | -------------------------------------------------------------------------------- /src/puzzlers/article26/q1/demo68.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | coordinateWithContext() 12 | } 13 | 14 | func coordinateWithContext() { 15 | total := 12 16 | var num int32 17 | fmt.Printf("The number: %d [with context.Context]\n", num) 18 | cxt, cancelFunc := context.WithCancel(context.Background()) 19 | for i := 1; i <= total; i++ { 20 | go addNum(&num, i, func() { 21 | if atomic.LoadInt32(&num) == int32(total) { 22 | cancelFunc() 23 | } 24 | }) 25 | } 26 | <-cxt.Done() 27 | fmt.Println("End.") 28 | } 29 | 30 | // addNum 用于原子地增加一次numP所指的变量的值。 31 | func addNum(numP *int32, id int, deferFunc func()) { 32 | defer func() { 33 | deferFunc() 34 | }() 35 | for i := 0; ; i++ { 36 | currNum := atomic.LoadInt32(numP) 37 | newNum := currNum + 1 38 | time.Sleep(time.Millisecond * 200) 39 | if atomic.CompareAndSwapInt32(numP, currNum, newNum) { 40 | fmt.Printf("The number: %d [%d-%d]\n", newNum, id, i) 41 | break 42 | } else { 43 | //fmt.Printf("The CAS operation failed. [%d-%d]\n", id, i) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/puzzlers/article37/common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "time" 9 | ) 10 | 11 | // OpFunc 代表包含高负载操作的函数。 12 | type OpFunc func() error 13 | 14 | // Execute 用于执行可以产生高负载的操作。 15 | func Execute(op OpFunc, times int) (err error) { 16 | if op == nil { 17 | return errors.New("nil operation function") 18 | } 19 | if times <= 0 { 20 | return fmt.Errorf("invalid times: %d", times) 21 | } 22 | var t1 time.Time 23 | defer func() { 24 | diff := time.Now().Sub(t1) 25 | fmt.Printf("(elapsed time: %s)\n", diff) 26 | if p := recover(); p != nil { 27 | err = fmt.Errorf("fatal error: %v", p) 28 | } 29 | }() 30 | t1 = time.Now() 31 | for i := 0; i < times; i++ { 32 | if err = op(); err != nil { 33 | return 34 | } 35 | time.Sleep(time.Microsecond) 36 | } 37 | return 38 | } 39 | 40 | // CreateFile 用于在当前目录下创建一个指定名称的文件。 41 | // 若同名文件已存在,则清空并复用。 42 | func CreateFile(dir, name string) (*os.File, error) { 43 | if dir == "" { 44 | var err error 45 | dir, err = os.Getwd() 46 | if err != nil { 47 | return nil, err 48 | } 49 | } 50 | path := filepath.Join(dir, name) 51 | return os.Create(path) 52 | } 53 | -------------------------------------------------------------------------------- /src/puzzlers/article26/q0/demo67.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | coordinateWithWaitGroup() 12 | } 13 | 14 | func coordinateWithWaitGroup() { 15 | total := 12 16 | stride := 3 17 | var num int32 18 | fmt.Printf("The number: %d [with sync.WaitGroup]\n", num) 19 | var wg sync.WaitGroup 20 | //fmt.Println("Start loop ...") 21 | for i := 1; i <= total; i = i + stride { 22 | //if i > 1 { 23 | // fmt.Println("Next iteration:") 24 | //} 25 | wg.Add(stride) 26 | for j := 0; j < stride; j++ { 27 | go addNum(&num, i+j, wg.Done) 28 | } 29 | wg.Wait() 30 | } 31 | fmt.Println("End.") 32 | } 33 | 34 | // addNum 用于原子地增加一次numP所指的变量的值。 35 | func addNum(numP *int32, id int, deferFunc func()) { 36 | defer func() { 37 | deferFunc() 38 | }() 39 | for i := 0; ; i++ { 40 | currNum := atomic.LoadInt32(numP) 41 | newNum := currNum + 1 42 | time.Sleep(time.Millisecond * 200) 43 | if atomic.CompareAndSwapInt32(numP, currNum, newNum) { 44 | fmt.Printf("The number: %d [%d-%d]\n", newNum, id, i) 45 | break 46 | } else { 47 | //fmt.Printf("The CAS operation failed. [%d-%d]\n", id, i) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/puzzlers/article7/q2/demo16.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | s6 := make([]int, 0) 8 | fmt.Printf("The capacity of s6: %d\n", cap(s6)) 9 | for i := 1; i <= 5; i++ { 10 | s6 = append(s6, i) 11 | fmt.Printf("s6(%d): len: %d, cap: %d\n", i, len(s6), cap(s6)) 12 | } 13 | fmt.Println() 14 | 15 | // 示例2。 16 | s7 := make([]int, 1024) 17 | fmt.Printf("The capacity of s7: %d\n", cap(s7)) 18 | s7e1 := append(s7, make([]int, 200)...) 19 | fmt.Printf("s7e1: len: %d, cap: %d\n", len(s7e1), cap(s7e1)) 20 | s7e2 := append(s7, make([]int, 400)...) 21 | fmt.Printf("s7e2: len: %d, cap: %d\n", len(s7e2), cap(s7e2)) 22 | s7e3 := append(s7, make([]int, 600)...) 23 | fmt.Printf("s7e3: len: %d, cap: %d\n", len(s7e3), cap(s7e3)) 24 | fmt.Println() 25 | 26 | // 示例3。 27 | s8 := make([]int, 10) 28 | fmt.Printf("The capacity of s8: %d\n", cap(s8)) 29 | s8a := append(s8, make([]int, 11)...) 30 | fmt.Printf("s8a: len: %d, cap: %d\n", len(s8a), cap(s8a)) 31 | s8b := append(s8a, make([]int, 23)...) 32 | fmt.Printf("s8b: len: %d, cap: %d\n", len(s8b), cap(s8b)) 33 | s8c := append(s8b, make([]int, 45)...) 34 | fmt.Printf("s8c: len: %d, cap: %d\n", len(s8c), cap(s8c)) 35 | } 36 | -------------------------------------------------------------------------------- /src/puzzlers/article14/q2/demo33.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Pet interface { 9 | Name() string 10 | Category() string 11 | } 12 | 13 | type Dog struct { 14 | name string // 名字。 15 | } 16 | 17 | func (dog *Dog) SetName(name string) { 18 | dog.name = name 19 | } 20 | 21 | func (dog Dog) Name() string { 22 | return dog.name 23 | } 24 | 25 | func (dog Dog) Category() string { 26 | return "dog" 27 | } 28 | 29 | func main() { 30 | // 示例1。 31 | var dog1 *Dog 32 | fmt.Println("The first dog is nil.") 33 | dog2 := dog1 34 | fmt.Println("The second dog is nil.") 35 | var pet Pet = dog2 36 | if pet == nil { 37 | fmt.Println("The pet is nil.") 38 | } else { 39 | fmt.Println("The pet is not nil.") 40 | } 41 | fmt.Printf("The type of pet is %T.\n", pet) 42 | fmt.Printf("The type of pet is %s.\n", reflect.TypeOf(pet).String()) 43 | fmt.Printf("The type of second dog is %T.\n", dog2) 44 | fmt.Println() 45 | 46 | // 示例2。 47 | wrap := func(dog *Dog) Pet { 48 | if dog == nil { 49 | return nil 50 | } 51 | return dog 52 | } 53 | pet = wrap(dog2) 54 | if pet == nil { 55 | fmt.Println("The pet is nil.") 56 | } else { 57 | fmt.Println("The pet is not nil.") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q0/demo52_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHello(t *testing.T) { 9 | var name string 10 | greeting, err := hello(name) 11 | if err == nil { 12 | t.Errorf("The error is nil, but it should not be. (name=%q)", 13 | name) 14 | } 15 | if greeting != "" { 16 | t.Errorf("Nonempty greeting, but it should not be. (name=%q)", 17 | name) 18 | } 19 | name = "Robert" 20 | greeting, err = hello(name) 21 | if err != nil { 22 | t.Errorf("The error is not nil, but it should be. (name=%q)", 23 | name) 24 | } 25 | if greeting == "" { 26 | t.Errorf("Empty greeting, but it should not be. (name=%q)", 27 | name) 28 | } 29 | expected := fmt.Sprintf("Hello, %s!", name) 30 | if greeting != expected { 31 | t.Errorf("The actual greeting %q is not the expected. (name=%q)", 32 | greeting, name) 33 | } 34 | t.Logf("The expected greeting is %q.\n", expected) 35 | } 36 | 37 | func testIntroduce(t *testing.T) { // 请注意这个测试函数的名称。 38 | intro := introduce() 39 | expected := "Welcome to my Golang column." 40 | if intro != expected { 41 | t.Errorf("The actual introduce %q is not the expected.", 42 | intro) 43 | } 44 | t.Logf("The expected introduce is %q.\n", expected) 45 | } 46 | -------------------------------------------------------------------------------- /src/puzzlers/article6/q2/demo13.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | // 重点1的示例。 9 | var srcInt = int16(-255) 10 | // 请注意,之所以要执行uint16(srcInt),是因为只有这样才能得到全二进制的表示。 11 | // 例如,fmt.Printf("%b", srcInt)将打印出"-11111111",后者是负数符号再加上srcInt的绝对值的补码。 12 | // 而fmt.Printf("%b", uint16(srcInt))才会打印出srcInt原值的补码"1111111100000001"。 13 | fmt.Printf("The complement of srcInt: %b (%b)\n", 14 | uint16(srcInt), srcInt) 15 | dstInt := int8(srcInt) 16 | fmt.Printf("The complement of dstInt: %b (%b)\n", 17 | uint8(dstInt), dstInt) 18 | fmt.Printf("The value of dstInt: %d\n", dstInt) 19 | fmt.Println() 20 | 21 | // 重点2的示例。 22 | fmt.Printf("The Replacement Character: %s\n", string(-1)) 23 | fmt.Printf("The Unicode codepoint of Replacement Character: %U\n", '�') 24 | fmt.Println() 25 | 26 | // 重点3的示例。 27 | srcStr := "你好" 28 | fmt.Printf("The string: %q\n", srcStr) 29 | fmt.Printf("The hex of %q: %x\n", srcStr, srcStr) 30 | fmt.Printf("The byte slice of %q: % x\n", srcStr, []byte(srcStr)) 31 | fmt.Printf("The string: %q\n", string([]byte{'\xe4', '\xbd', '\xa0', '\xe5', '\xa5', '\xbd'})) 32 | fmt.Printf("The rune slice of %q: %U\n", srcStr, []rune(srcStr)) 33 | fmt.Printf("The string: %q\n", string([]rune{'\u4F60', '\u597D'})) 34 | } 35 | -------------------------------------------------------------------------------- /src/puzzlers/article11/q2/demo24.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | example1() 11 | example2() 12 | } 13 | 14 | // 示例1。 15 | func example1() { 16 | // 准备好几个通道。 17 | intChannels := [3]chan int{ 18 | make(chan int, 1), 19 | make(chan int, 1), 20 | make(chan int, 1), 21 | } 22 | // 随机选择一个通道,并向它发送元素值。 23 | index := rand.Intn(3) 24 | fmt.Printf("The index: %d\n", index) 25 | intChannels[index] <- index 26 | // 哪一个通道中有可取的元素值,哪个对应的分支就会被执行。 27 | select { 28 | case <-intChannels[0]: 29 | fmt.Println("The first candidate case is selected.") 30 | case <-intChannels[1]: 31 | fmt.Println("The second candidate case is selected.") 32 | case elem := <-intChannels[2]: 33 | fmt.Printf("The third candidate case is selected, the element is %d.\n", elem) 34 | default: 35 | fmt.Println("No candidate case is selected!") 36 | } 37 | } 38 | 39 | // 示例2。 40 | func example2() { 41 | intChan := make(chan int, 1) 42 | // 一秒后关闭通道。 43 | time.AfterFunc(time.Second, func() { 44 | close(intChan) 45 | }) 46 | select { 47 | case _, ok := <-intChan: 48 | if !ok { 49 | fmt.Println("The candidate case is closed.") 50 | break 51 | } 52 | fmt.Println("The candidate case is selected.") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/puzzlers/article32/q2/demo83.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | ) 7 | 8 | func main() { 9 | comment := "Because these interfaces and primitives wrap lower-level operations with various implementations, " + 10 | "unless otherwise informed clients should not assume they are safe for parallel execution." 11 | basicReader := strings.NewReader(comment) 12 | basicWriter := new(strings.Builder) 13 | 14 | // 示例1。 15 | reader1 := io.LimitReader(basicReader, 98) 16 | _ = interface{}(reader1).(io.Reader) 17 | 18 | // 示例2。 19 | reader2 := io.NewSectionReader(basicReader, 98, 89) 20 | _ = interface{}(reader2).(io.Reader) 21 | _ = interface{}(reader2).(io.ReaderAt) 22 | _ = interface{}(reader2).(io.Seeker) 23 | 24 | // 示例3。 25 | reader3 := io.TeeReader(basicReader, basicWriter) 26 | _ = interface{}(reader3).(io.Reader) 27 | 28 | // 示例4。 29 | reader4 := io.MultiReader(reader1) 30 | _ = interface{}(reader4).(io.Reader) 31 | 32 | // 示例5。 33 | writer1 := io.MultiWriter(basicWriter) 34 | _ = interface{}(writer1).(io.Writer) 35 | 36 | // 示例6。 37 | pReader, pWriter := io.Pipe() 38 | _ = interface{}(pReader).(io.Reader) 39 | _ = interface{}(pReader).(io.Closer) 40 | _ = interface{}(pWriter).(io.Writer) 41 | _ = interface{}(pWriter).(io.Closer) 42 | } 43 | -------------------------------------------------------------------------------- /src/puzzlers/article20/q2/demo53_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHello(t *testing.T) { 9 | var name string 10 | greeting, err := hello(name) 11 | if err == nil { 12 | t.Errorf("The error is nil, but it should not be. (name=%q)", 13 | name) 14 | } 15 | if greeting != "" { 16 | t.Errorf("Nonempty greeting, but it should not be. (name=%q)", 17 | name) 18 | } 19 | name = "Robert" 20 | greeting, err = hello(name) 21 | if err != nil { 22 | t.Errorf("The error is not nil, but it should be. (name=%q)", 23 | name) 24 | } 25 | if greeting == "" { 26 | t.Errorf("Empty greeting, but it should not be. (name=%q)", 27 | name) 28 | } 29 | expected := fmt.Sprintf("Hello, %s!", name) 30 | if greeting != expected { 31 | t.Errorf("The actual greeting %q is not the expected. (name=%q)", 32 | greeting, name) 33 | } 34 | t.Logf("The expected greeting is %q.\n", expected) 35 | } 36 | 37 | func TestIntroduce(t *testing.T) { 38 | intro := introduce() 39 | expected := "Welcome to my Golang column." 40 | if intro != expected { 41 | t.Errorf("The actual introduce %q is not the expected.", 42 | intro) 43 | } 44 | t.Logf("The expected introduce is %q.\n", expected) 45 | } 46 | 47 | func TestFail(t *testing.T) { 48 | //t.Fail() 49 | t.FailNow() // 此调用会让当前的测试立即失败。 50 | t.Log("Failed.") 51 | } 52 | -------------------------------------------------------------------------------- /src/puzzlers/article12/q3/demo28.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | array1 := [3]string{"a", "b", "c"} 8 | fmt.Printf("The array: %v\n", array1) 9 | array2 := modifyArray(array1) 10 | fmt.Printf("The modified array: %v\n", array2) 11 | fmt.Printf("The original array: %v\n", array1) 12 | fmt.Println() 13 | 14 | // 示例2。 15 | slice1 := []string{"x", "y", "z"} 16 | fmt.Printf("The slice: %v\n", slice1) 17 | slice2 := modifySlice(slice1) 18 | fmt.Printf("The modified slice: %v\n", slice2) 19 | fmt.Printf("The original slice: %v\n", slice1) 20 | fmt.Println() 21 | 22 | // 示例3。 23 | complexArray1 := [3][]string{ 24 | []string{"d", "e", "f"}, 25 | []string{"g", "h", "i"}, 26 | []string{"j", "k", "l"}, 27 | } 28 | fmt.Printf("The complex array: %v\n", complexArray1) 29 | complexArray2 := modifyComplexArray(complexArray1) 30 | fmt.Printf("The modified complex array: %v\n", complexArray2) 31 | fmt.Printf("The original complex array: %v\n", complexArray1) 32 | } 33 | 34 | // 示例1。 35 | func modifyArray(a [3]string) [3]string { 36 | a[1] = "x" 37 | return a 38 | } 39 | 40 | // 示例2。 41 | func modifySlice(a []string) []string { 42 | a[1] = "i" 43 | return a 44 | } 45 | 46 | // 示例3。 47 | func modifyComplexArray(a [3][]string) [3][]string { 48 | a[1][1] = "s" 49 | a[2] = []string{"o", "p", "q"} 50 | return a 51 | } 52 | -------------------------------------------------------------------------------- /src/puzzlers/article35/q2/demo92.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | ) 8 | 9 | type dailArgs struct { 10 | network string 11 | address string 12 | timeout time.Duration 13 | } 14 | 15 | func main() { 16 | dialArgsList := []dailArgs{ 17 | { 18 | "tcp", 19 | "google.cn:80", 20 | time.Millisecond * 500, 21 | }, 22 | { 23 | "tcp", 24 | "google.com:80", 25 | time.Second * 2, 26 | }, 27 | { 28 | // 如果在这种情况下发生的错误是: 29 | // "connect: operation timed out", 30 | // 那么代表着什么呢? 31 | // 32 | // 简单来说,此错误表示底层的socket在连接网络服务的时候先超时了。 33 | // 这时抛出的其实是'syscall.ETIMEDOUT'常量代表的错误值。 34 | "tcp", 35 | "google.com:80", 36 | time.Minute * 4, 37 | }, 38 | } 39 | for _, args := range dialArgsList { 40 | fmt.Printf("Dial %q with network %q and timeout %s ...\n", 41 | args.address, args.network, args.timeout) 42 | ts1 := time.Now() 43 | conn, err := net.DialTimeout(args.network, args.address, args.timeout) 44 | ts2 := time.Now() 45 | fmt.Printf("Elapsed time: %s\n", time.Duration(ts2.Sub(ts1))) 46 | if err != nil { 47 | fmt.Printf("dial error: %v\n", err) 48 | fmt.Println() 49 | continue 50 | } 51 | defer conn.Close() 52 | fmt.Printf("The local address: %s\n", conn.LocalAddr()) 53 | fmt.Printf("The remote address: %s\n", conn.RemoteAddr()) 54 | fmt.Println() 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/puzzlers/article14/q3/demo34.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Animal interface { 8 | // ScientificName 用于获取动物的学名。 9 | ScientificName() string 10 | // Category 用于获取动物的基本分类。 11 | Category() string 12 | } 13 | 14 | type Named interface { 15 | // Name 用于获取名字。 16 | Name() string 17 | } 18 | 19 | type Pet interface { 20 | Animal 21 | Named 22 | } 23 | 24 | type PetTag struct { 25 | name string 26 | owner string 27 | } 28 | 29 | func (pt PetTag) Name() string { 30 | return pt.name 31 | } 32 | 33 | func (pt PetTag) Owner() string { 34 | return pt.owner 35 | } 36 | 37 | type Dog struct { 38 | PetTag 39 | scientificName string 40 | } 41 | 42 | func (dog Dog) ScientificName() string { 43 | return dog.scientificName 44 | } 45 | 46 | func (dog Dog) Category() string { 47 | return "dog" 48 | } 49 | 50 | func main() { 51 | petTag := PetTag{name: "little pig"} 52 | _, ok := interface{}(petTag).(Named) 53 | fmt.Printf("PetTag implements interface Named: %v\n", ok) 54 | dog := Dog{ 55 | PetTag: petTag, 56 | scientificName: "Labrador Retriever", 57 | } 58 | _, ok = interface{}(dog).(Animal) 59 | fmt.Printf("Dog implements interface Animal: %v\n", ok) 60 | _, ok = interface{}(dog).(Named) 61 | fmt.Printf("Dog implements interface Named: %v\n", ok) 62 | _, ok = interface{}(dog).(Pet) 63 | fmt.Printf("Dog implements interface Pet: %v\n", ok) 64 | } 65 | -------------------------------------------------------------------------------- /src/puzzlers/article14/q1/demo32.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Pet interface { 8 | Name() string 9 | Category() string 10 | } 11 | 12 | type Dog struct { 13 | name string // 名字。 14 | } 15 | 16 | func (dog *Dog) SetName(name string) { 17 | dog.name = name 18 | } 19 | 20 | func (dog Dog) Name() string { 21 | return dog.name 22 | } 23 | 24 | func (dog Dog) Category() string { 25 | return "dog" 26 | } 27 | 28 | func main() { 29 | // 示例1。 30 | dog := Dog{"little pig"} 31 | fmt.Printf("The dog's name is %q.\n", dog.Name()) 32 | var pet Pet = dog 33 | dog.SetName("monster") 34 | fmt.Printf("The dog's name is %q.\n", dog.Name()) 35 | fmt.Printf("This pet is a %s, the name is %q.\n", 36 | pet.Category(), pet.Name()) 37 | fmt.Println() 38 | 39 | // 示例2。 40 | dog1 := Dog{"little pig"} 41 | fmt.Printf("The name of first dog is %q.\n", dog1.Name()) 42 | dog2 := dog1 43 | fmt.Printf("The name of second dog is %q.\n", dog2.Name()) 44 | dog1.name = "monster" 45 | fmt.Printf("The name of first dog is %q.\n", dog1.Name()) 46 | fmt.Printf("The name of second dog is %q.\n", dog2.Name()) 47 | fmt.Println() 48 | 49 | // 示例3。 50 | dog = Dog{"little pig"} 51 | fmt.Printf("The dog's name is %q.\n", dog.Name()) 52 | pet = &dog 53 | dog.SetName("monster") 54 | fmt.Printf("The dog's name is %q.\n", dog.Name()) 55 | fmt.Printf("This pet is a %s, the name is %q.\n", 56 | pet.Category(), pet.Name()) 57 | } 58 | -------------------------------------------------------------------------------- /src/puzzlers/article23/q1/demo61.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // mailbox 代表信箱。 11 | // 0代表信箱是空的,1代表信箱是满的。 12 | var mailbox uint8 13 | // lock 代表信箱上的锁。 14 | var lock sync.RWMutex 15 | // sendCond 代表专用于发信的条件变量。 16 | sendCond := sync.NewCond(&lock) 17 | // recvCond 代表专用于收信的条件变量。 18 | recvCond := sync.NewCond(lock.RLocker()) 19 | 20 | // sign 用于传递演示完成的信号。 21 | sign := make(chan struct{}, 3) 22 | max := 5 23 | go func(max int) { // 用于发信。 24 | defer func() { 25 | sign <- struct{}{} 26 | }() 27 | for i := 1; i <= max; i++ { 28 | time.Sleep(time.Millisecond * 500) 29 | lock.Lock() 30 | for mailbox == 1 { 31 | sendCond.Wait() 32 | } 33 | log.Printf("sender [%d]: the mailbox is empty.", i) 34 | mailbox = 1 35 | log.Printf("sender [%d]: the letter has been sent.", i) 36 | lock.Unlock() 37 | recvCond.Signal() 38 | } 39 | }(max) 40 | go func(max int) { // 用于收信。 41 | defer func() { 42 | sign <- struct{}{} 43 | }() 44 | for j := 1; j <= max; j++ { 45 | time.Sleep(time.Millisecond * 500) 46 | lock.RLock() 47 | for mailbox == 0 { 48 | recvCond.Wait() 49 | } 50 | log.Printf("receiver [%d]: the mailbox is full.", j) 51 | mailbox = 0 52 | log.Printf("receiver [%d]: the letter has been received.", j) 53 | lock.RUnlock() 54 | sendCond.Signal() 55 | } 56 | }(max) 57 | 58 | <-sign 59 | <-sign 60 | } 61 | -------------------------------------------------------------------------------- /src/puzzlers/article25/q0/demo65.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | coordinateWithChan() 12 | fmt.Println() 13 | coordinateWithWaitGroup() 14 | } 15 | 16 | func coordinateWithChan() { 17 | sign := make(chan struct{}, 2) 18 | num := int32(0) 19 | fmt.Printf("The number: %d [with chan struct{}]\n", num) 20 | max := int32(10) 21 | go addNum(&num, 1, max, func() { 22 | sign <- struct{}{} 23 | }) 24 | go addNum(&num, 2, max, func() { 25 | sign <- struct{}{} 26 | }) 27 | <-sign 28 | <-sign 29 | } 30 | 31 | func coordinateWithWaitGroup() { 32 | var wg sync.WaitGroup 33 | wg.Add(2) 34 | num := int32(0) 35 | fmt.Printf("The number: %d [with sync.WaitGroup]\n", num) 36 | max := int32(10) 37 | go addNum(&num, 3, max, wg.Done) 38 | go addNum(&num, 4, max, wg.Done) 39 | wg.Wait() 40 | } 41 | 42 | // addNum 用于原子地增加numP所指的变量的值。 43 | func addNum(numP *int32, id, max int32, deferFunc func()) { 44 | defer func() { 45 | deferFunc() 46 | }() 47 | for i := 0; ; i++ { 48 | currNum := atomic.LoadInt32(numP) 49 | if currNum >= max { 50 | break 51 | } 52 | newNum := currNum + 2 53 | time.Sleep(time.Millisecond * 200) 54 | if atomic.CompareAndSwapInt32(numP, currNum, newNum) { 55 | fmt.Printf("The number: %d [%d-%d]\n", newNum, id, i) 56 | } else { 57 | fmt.Printf("The CAS operation failed. [%d-%d]\n", id, i) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/puzzlers/article34/q3/demo89.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | type argDesc struct { 10 | action string 11 | flag int 12 | perm os.FileMode 13 | } 14 | 15 | func main() { 16 | // 示例1。 17 | fmt.Printf("The mode for dir:\n%32b\n", os.ModeDir) 18 | fmt.Printf("The mode for named pipe:\n%32b\n", os.ModeNamedPipe) 19 | fmt.Printf("The mode for all of the irregular files:\n%32b\n", os.ModeType) 20 | fmt.Printf("The mode for permissions:\n%32b\n", os.ModePerm) 21 | fmt.Println() 22 | 23 | // 示例2。 24 | fileName1 := "something3.txt" 25 | filePath1 := filepath.Join(os.TempDir(), fileName1) 26 | fmt.Printf("The file path: %s\n", filePath1) 27 | 28 | argDescList := []argDesc{ 29 | { 30 | "Create", 31 | os.O_RDWR | os.O_CREATE, 32 | 0644, 33 | }, 34 | { 35 | "Reuse", 36 | os.O_RDWR | os.O_TRUNC, 37 | 0666, 38 | }, 39 | { 40 | "Open", 41 | os.O_RDWR | os.O_APPEND, 42 | 0777, 43 | }, 44 | } 45 | 46 | defer os.Remove(filePath1) 47 | for _, v := range argDescList { 48 | fmt.Printf("%s the file with perm %o ...\n", v.action, v.perm) 49 | file1, err := os.OpenFile(filePath1, v.flag, v.perm) 50 | if err != nil { 51 | fmt.Printf("error: %v\n", err) 52 | continue 53 | } 54 | info1, err := file1.Stat() 55 | if err != nil { 56 | fmt.Printf("error: %v\n", err) 57 | continue 58 | } 59 | fmt.Printf("The file permissions: %o\n", info1.Mode().Perm()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/puzzlers/article36/q2/demo95.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "sync" 8 | ) 9 | 10 | func main() { 11 | var wg sync.WaitGroup 12 | wg.Add(2) 13 | 14 | // 示例1。 15 | go startServer1(&wg) 16 | 17 | // 示例2。 18 | go startServer2(&wg) 19 | 20 | wg.Wait() 21 | } 22 | 23 | func startServer1(wg *sync.WaitGroup) { 24 | defer wg.Done() 25 | var httpServer1 http.Server 26 | httpServer1.Addr = "127.0.0.1:8080" 27 | // 由于我们没有定制handler,所以这个网络服务对任何请求都只会响应404。 28 | if err := httpServer1.ListenAndServe(); err != nil { 29 | if err == http.ErrServerClosed { 30 | log.Println("HTTP server 1 closed.") 31 | } else { 32 | log.Printf("HTTP server 1 error: %v\n", err) 33 | } 34 | } 35 | } 36 | 37 | func startServer2(wg *sync.WaitGroup) { 38 | defer wg.Done() 39 | mux1 := http.NewServeMux() 40 | mux1.HandleFunc("/hi", func(w http.ResponseWriter, req *http.Request) { 41 | if req.URL.Path != "/hi" { 42 | http.NotFound(w, req) 43 | return 44 | } 45 | name := req.FormValue("name") 46 | if name == "" { 47 | fmt.Fprint(w, "Welcome!") 48 | } else { 49 | fmt.Fprintf(w, "Welcome, %s!", name) 50 | } 51 | }) 52 | httpServer2 := http.Server{ 53 | Addr: "127.0.0.1:8081", 54 | Handler: mux1, 55 | } 56 | if err := httpServer2.ListenAndServe(); err != nil { 57 | if err == http.ErrServerClosed { 58 | log.Println("HTTP server 2 closed.") 59 | } else { 60 | log.Printf("HTTP server 2 error: %v\n", err) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/puzzlers/article13/q0/demo29.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // 示例1。 6 | // AnimalCategory 代表动物分类学中的基本分类法。 7 | type AnimalCategory struct { 8 | kingdom string // 界。 9 | phylum string // 门。 10 | class string // 纲。 11 | order string // 目。 12 | family string // 科。 13 | genus string // 属。 14 | species string // 种。 15 | } 16 | 17 | func (ac AnimalCategory) String() string { 18 | return fmt.Sprintf("%s%s%s%s%s%s%s", 19 | ac.kingdom, ac.phylum, ac.class, ac.order, 20 | ac.family, ac.genus, ac.species) 21 | } 22 | 23 | // 示例2。 24 | type Animal struct { 25 | scientificName string // 学名。 26 | AnimalCategory // 动物基本分类。 27 | } 28 | 29 | // 该方法会"屏蔽"掉嵌入字段中的同名方法。 30 | func (a Animal) String() string { 31 | return fmt.Sprintf("%s (category: %s)", 32 | a.scientificName, a.AnimalCategory) 33 | } 34 | 35 | // 示例3。 36 | type Cat struct { 37 | name string 38 | Animal 39 | } 40 | 41 | // 该方法会"屏蔽"掉嵌入字段中的同名方法。 42 | func (cat Cat) String() string { 43 | return fmt.Sprintf("%s (category: %s, name: %q)", 44 | cat.scientificName, cat.Animal.AnimalCategory, cat.name) 45 | } 46 | 47 | func main() { 48 | // 示例1。 49 | category := AnimalCategory{species: "cat"} 50 | fmt.Printf("The animal category: %s\n", category) 51 | 52 | // 示例2。 53 | animal := Animal{ 54 | scientificName: "American Shorthair", 55 | AnimalCategory: category, 56 | } 57 | fmt.Printf("The animal: %s\n", animal) 58 | 59 | // 示例3。 60 | cat := Cat{ 61 | name: "little pig", 62 | Animal: animal, 63 | } 64 | fmt.Printf("The cat: %s\n", cat) 65 | } 66 | -------------------------------------------------------------------------------- /src/puzzlers/article13/q3/demo30.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Cat struct { 6 | name string // 名字。 7 | scientificName string // 学名。 8 | category string // 动物学基本分类。 9 | } 10 | 11 | func New(name, scientificName, category string) Cat { 12 | return Cat{ 13 | name: name, 14 | scientificName: scientificName, 15 | category: category, 16 | } 17 | } 18 | 19 | func (cat *Cat) SetName(name string) { 20 | cat.name = name 21 | } 22 | 23 | func (cat Cat) SetNameOfCopy(name string) { 24 | cat.name = name 25 | } 26 | 27 | func (cat Cat) Name() string { 28 | return cat.name 29 | } 30 | 31 | func (cat Cat) ScientificName() string { 32 | return cat.scientificName 33 | } 34 | 35 | func (cat Cat) Category() string { 36 | return cat.category 37 | } 38 | 39 | func (cat Cat) String() string { 40 | return fmt.Sprintf("%s (category: %s, name: %q)", 41 | cat.scientificName, cat.category, cat.name) 42 | } 43 | 44 | func main() { 45 | cat := New("little pig", "American Shorthair", "cat") 46 | cat.SetName("monster") // (&cat).SetName("monster") 47 | fmt.Printf("The cat: %s\n", cat) 48 | 49 | cat.SetNameOfCopy("little pig") 50 | fmt.Printf("The cat: %s\n", cat) 51 | 52 | type Pet interface { 53 | SetName(name string) 54 | Name() string 55 | Category() string 56 | ScientificName() string 57 | } 58 | 59 | _, ok := interface{}(cat).(Pet) 60 | fmt.Printf("Cat implements interface Pet: %v\n", ok) 61 | _, ok = interface{}(&cat).(Pet) 62 | fmt.Printf("*Cat implements interface Pet: %v\n", ok) 63 | } 64 | -------------------------------------------------------------------------------- /src/puzzlers/article30/q3/demo77.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | // 示例1。 11 | reader1 := strings.NewReader( 12 | "NewReader returns a new Reader reading from s. " + 13 | "It is similar to bytes.NewBufferString but more efficient and read-only.") 14 | fmt.Printf("The size of reader: %d\n", reader1.Size()) 15 | fmt.Printf("The reading index in reader: %d\n", 16 | reader1.Size()-int64(reader1.Len())) 17 | 18 | buf1 := make([]byte, 47) 19 | n, _ := reader1.Read(buf1) 20 | fmt.Printf("%d bytes were read. (call Read)\n", n) 21 | fmt.Printf("The reading index in reader: %d\n", 22 | reader1.Size()-int64(reader1.Len())) 23 | fmt.Println() 24 | 25 | // 示例2。 26 | buf2 := make([]byte, 21) 27 | offset1 := int64(64) 28 | n, _ = reader1.ReadAt(buf2, offset1) 29 | fmt.Printf("%d bytes were read. (call ReadAt, offset: %d)\n", n, offset1) 30 | fmt.Printf("The reading index in reader: %d\n", 31 | reader1.Size()-int64(reader1.Len())) 32 | fmt.Println() 33 | 34 | // 示例3。 35 | offset2 := int64(17) 36 | expectedIndex := reader1.Size() - int64(reader1.Len()) + offset2 37 | fmt.Printf("Seek with offset %d and whence %d ...\n", offset2, io.SeekCurrent) 38 | readingIndex, _ := reader1.Seek(offset2, io.SeekCurrent) 39 | fmt.Printf("The reading index in reader: %d (returned by Seek)\n", readingIndex) 40 | fmt.Printf("The reading index in reader: %d (computed by me)\n", expectedIndex) 41 | 42 | n, _ = reader1.Read(buf2) 43 | fmt.Printf("%d bytes were read. (call Read)\n", n) 44 | fmt.Printf("The reading index in reader: %d\n", 45 | reader1.Size()-int64(reader1.Len())) 46 | } 47 | -------------------------------------------------------------------------------- /src/puzzlers/article32/q0/demo81.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | // 示例1。 12 | builder := new(strings.Builder) 13 | _ = interface{}(builder).(io.Writer) 14 | _ = interface{}(builder).(io.ByteWriter) 15 | _ = interface{}(builder).(fmt.Stringer) 16 | 17 | // 示例2。 18 | reader := strings.NewReader("") 19 | _ = interface{}(reader).(io.Reader) 20 | _ = interface{}(reader).(io.ReaderAt) 21 | _ = interface{}(reader).(io.ByteReader) 22 | _ = interface{}(reader).(io.RuneReader) 23 | _ = interface{}(reader).(io.Seeker) 24 | _ = interface{}(reader).(io.ByteScanner) 25 | _ = interface{}(reader).(io.RuneScanner) 26 | _ = interface{}(reader).(io.WriterTo) 27 | 28 | // 示例3。 29 | buffer := bytes.NewBuffer([]byte{}) 30 | _ = interface{}(buffer).(io.Reader) 31 | _ = interface{}(buffer).(io.ByteReader) 32 | _ = interface{}(buffer).(io.RuneReader) 33 | _ = interface{}(buffer).(io.ByteScanner) 34 | _ = interface{}(buffer).(io.RuneScanner) 35 | _ = interface{}(buffer).(io.WriterTo) 36 | 37 | _ = interface{}(buffer).(io.Writer) 38 | _ = interface{}(buffer).(io.ByteWriter) 39 | _ = interface{}(buffer).(io.ReaderFrom) 40 | 41 | _ = interface{}(buffer).(fmt.Stringer) 42 | 43 | // 示例4。 44 | src := strings.NewReader( 45 | "CopyN copies n bytes (or until an error) from src to dst. " + 46 | "It returns the number of bytes copied and " + 47 | "the earliest error encountered while copying.") 48 | dst := new(strings.Builder) 49 | written, err := io.CopyN(dst, src, 58) 50 | if err != nil { 51 | fmt.Printf("error: %v\n", err) 52 | } else { 53 | fmt.Printf("Written(%d): %q\n", written, dst.String()) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/puzzlers/article18/q2/demo46.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strconv" 8 | ) 9 | 10 | // underlyingError 会返回已知的操作系统相关错误的潜在错误值。 11 | func underlyingError(err error) error { 12 | switch err := err.(type) { 13 | case *os.PathError: 14 | return err.Err 15 | case *os.LinkError: 16 | return err.Err 17 | case *os.SyscallError: 18 | return err.Err 19 | case *exec.Error: 20 | return err.Err 21 | } 22 | return err 23 | } 24 | 25 | // Errno 代表某种错误的类型。 26 | type Errno int 27 | 28 | func (e Errno) Error() string { 29 | return "errno " + strconv.Itoa(int(e)) 30 | } 31 | 32 | func main() { 33 | var err error 34 | // 示例1。 35 | _, err = exec.LookPath(os.DevNull) 36 | fmt.Printf("error: %s\n", err) 37 | if execErr, ok := err.(*exec.Error); ok { 38 | execErr.Name = os.TempDir() 39 | execErr.Err = os.ErrNotExist 40 | } 41 | fmt.Printf("error: %s\n", err) 42 | fmt.Println() 43 | 44 | // 示例2。 45 | err = os.ErrPermission 46 | if os.IsPermission(err) { 47 | fmt.Printf("error(permission): %s\n", err) 48 | } else { 49 | fmt.Printf("error(other): %s\n", err) 50 | } 51 | os.ErrPermission = os.ErrExist 52 | // 上面这行代码修改了os包中已定义的错误值。 53 | // 这样做会导致下面判断的结果不正确。 54 | // 并且,这会影响到当前Go程序中所有的此类判断。 55 | // 所以,一定要避免这样做! 56 | if os.IsPermission(err) { 57 | fmt.Printf("error(permission): %s\n", err) 58 | } else { 59 | fmt.Printf("error(other): %s\n", err) 60 | } 61 | fmt.Println() 62 | 63 | // 示例3。 64 | const ( 65 | ERR0 = Errno(0) 66 | ERR1 = Errno(1) 67 | ERR2 = Errno(2) 68 | ) 69 | var myErr error = Errno(0) 70 | switch myErr { 71 | case ERR0: 72 | fmt.Println("ERR0") 73 | case ERR1: 74 | fmt.Println("ERR1") 75 | case ERR2: 76 | fmt.Println("ERR2") 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/puzzlers/article25/q2/demo66.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "sync" 7 | "sync/atomic" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | // 示例1。 13 | var counter uint32 14 | var once sync.Once 15 | once.Do(func() { 16 | atomic.AddUint32(&counter, 1) 17 | }) 18 | fmt.Printf("The counter: %d\n", counter) 19 | once.Do(func() { 20 | atomic.AddUint32(&counter, 2) 21 | }) 22 | fmt.Printf("The counter: %d\n", counter) 23 | fmt.Println() 24 | 25 | // 示例2。 26 | once = sync.Once{} 27 | var wg sync.WaitGroup 28 | wg.Add(3) 29 | go func() { 30 | defer wg.Done() 31 | once.Do(func() { 32 | for i := 0; i < 3; i++ { 33 | fmt.Printf("Do task. [1-%d]\n", i) 34 | time.Sleep(time.Second) 35 | } 36 | }) 37 | fmt.Println("Done. [1]") 38 | }() 39 | go func() { 40 | defer wg.Done() 41 | time.Sleep(time.Millisecond * 500) 42 | once.Do(func() { 43 | fmt.Println("Do task. [2]") 44 | }) 45 | fmt.Println("Done. [2]") 46 | }() 47 | go func() { 48 | defer wg.Done() 49 | time.Sleep(time.Millisecond * 500) 50 | once.Do(func() { 51 | fmt.Println("Do task. [3]") 52 | }) 53 | fmt.Println("Done. [3]") 54 | }() 55 | wg.Wait() 56 | fmt.Println() 57 | 58 | // 示例3。 59 | once = sync.Once{} 60 | wg.Add(2) 61 | go func() { 62 | defer wg.Done() 63 | defer func() { 64 | if p := recover(); p != nil { 65 | fmt.Printf("fatal error: %v\n", p) 66 | } 67 | }() 68 | once.Do(func() { 69 | fmt.Println("Do task. [4]") 70 | panic(errors.New("something wrong")) 71 | fmt.Println("Done. [4]") 72 | }) 73 | }() 74 | go func() { 75 | defer wg.Done() 76 | time.Sleep(time.Millisecond * 500) 77 | once.Do(func() { 78 | fmt.Println("Do task. [5]") 79 | }) 80 | fmt.Println("Done. [5]") 81 | }() 82 | wg.Wait() 83 | } 84 | -------------------------------------------------------------------------------- /src/puzzlers/article22/q0/demo58.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "log" 10 | "sync" 11 | ) 12 | 13 | // protecting 用于指示是否使用互斥锁来保护数据写入。 14 | // 若值等于0则表示不使用,若值大于0则表示使用。 15 | // 改变该变量的值,然后多运行几次程序,并观察程序打印的内容。 16 | var protecting uint 17 | 18 | func init() { 19 | flag.UintVar(&protecting, "protecting", 1, 20 | "It indicates whether to use a mutex to protect data writing.") 21 | } 22 | 23 | func main() { 24 | flag.Parse() 25 | // buffer 代表缓冲区。 26 | var buffer bytes.Buffer 27 | 28 | const ( 29 | max1 = 5 // 代表启用的goroutine的数量。 30 | max2 = 10 // 代表每个goroutine需要写入的数据块的数量。 31 | max3 = 10 // 代表每个数据块中需要有多少个重复的数字。 32 | ) 33 | 34 | // mu 代表以下流程要使用的互斥锁。 35 | var mu sync.Mutex 36 | // sign 代表信号的通道。 37 | sign := make(chan struct{}, max1) 38 | 39 | for i := 1; i <= max1; i++ { 40 | go func(id int, writer io.Writer) { 41 | defer func() { 42 | sign <- struct{}{} 43 | }() 44 | for j := 1; j <= max2; j++ { 45 | // 准备数据。 46 | header := fmt.Sprintf("\n[id: %d, iteration: %d]", 47 | id, j) 48 | data := fmt.Sprintf(" %d", id*j) 49 | // 写入数据。 50 | if protecting > 0 { 51 | mu.Lock() 52 | } 53 | _, err := writer.Write([]byte(header)) 54 | if err != nil { 55 | log.Printf("error: %s [%d]", err, id) 56 | } 57 | for k := 0; k < max3; k++ { 58 | _, err := writer.Write([]byte(data)) 59 | if err != nil { 60 | log.Printf("error: %s [%d]", err, id) 61 | } 62 | } 63 | if protecting > 0 { 64 | mu.Unlock() 65 | } 66 | } 67 | }(i, &buffer) 68 | } 69 | 70 | for i := 0; i < max1; i++ { 71 | <-sign 72 | } 73 | data, err := ioutil.ReadAll(&buffer) 74 | if err != nil { 75 | log.Fatalf("fatal error: %s", err) 76 | } 77 | log.Printf("The contents:\n%s", data) 78 | } 79 | -------------------------------------------------------------------------------- /src/puzzlers/article22/q2/demo60.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // counter 代表计数器。 10 | type counter struct { 11 | num uint // 计数。 12 | mu sync.RWMutex // 读写锁。 13 | } 14 | 15 | // number 会返回当前的计数。 16 | func (c *counter) number() uint { 17 | c.mu.RLock() 18 | defer c.mu.RUnlock() 19 | return c.num 20 | } 21 | 22 | // add 会增加计数器的值,并会返回增加后的计数。 23 | func (c *counter) add(increment uint) uint { 24 | c.mu.Lock() 25 | defer c.mu.Unlock() 26 | c.num += increment 27 | return c.num 28 | } 29 | 30 | func main() { 31 | c := counter{} 32 | count(&c) 33 | redundantUnlock() 34 | } 35 | 36 | func count(c *counter) { 37 | // sign 用于传递演示完成的信号。 38 | sign := make(chan struct{}, 3) 39 | go func() { // 用于增加计数。 40 | defer func() { 41 | sign <- struct{}{} 42 | }() 43 | for i := 1; i <= 10; i++ { 44 | time.Sleep(time.Millisecond * 500) 45 | c.add(1) 46 | } 47 | }() 48 | go func() { 49 | defer func() { 50 | sign <- struct{}{} 51 | }() 52 | for j := 1; j <= 20; j++ { 53 | time.Sleep(time.Millisecond * 200) 54 | log.Printf("The number in counter: %d [%d-%d]", 55 | c.number(), 1, j) 56 | } 57 | }() 58 | go func() { 59 | defer func() { 60 | sign <- struct{}{} 61 | }() 62 | for k := 1; k <= 20; k++ { 63 | time.Sleep(time.Millisecond * 300) 64 | log.Printf("The number in counter: %d [%d-%d]", 65 | c.number(), 2, k) 66 | } 67 | }() 68 | <-sign 69 | <-sign 70 | <-sign 71 | } 72 | 73 | func redundantUnlock() { 74 | var rwMu sync.RWMutex 75 | 76 | // 示例1。 77 | //rwMu.Unlock() // 这里会引发panic。 78 | 79 | // 示例2。 80 | //rwMu.RUnlock() // 这里会引发panic。 81 | 82 | // 示例3。 83 | rwMu.RLock() 84 | //rwMu.Unlock() // 这里会引发panic。 85 | rwMu.RUnlock() 86 | 87 | // 示例4。 88 | rwMu.Lock() 89 | //rwMu.RUnlock() // 这里会引发panic。 90 | rwMu.Unlock() 91 | } 92 | -------------------------------------------------------------------------------- /src/puzzlers/article15/q1/demo35.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Named interface { 4 | // Name 用于获取名字。 5 | Name() string 6 | } 7 | 8 | type Dog struct { 9 | name string 10 | } 11 | 12 | func (dog *Dog) SetName(name string) { 13 | dog.name = name 14 | } 15 | 16 | func (dog Dog) Name() string { 17 | return dog.name 18 | } 19 | 20 | func main() { 21 | // 示例1。 22 | const num = 123 23 | //_ = &num // 常量不可寻址。 24 | //_ = &(123) // 基本类型值的字面量不可寻址。 25 | 26 | var str = "abc" 27 | _ = str 28 | //_ = &(str[0]) // 对字符串变量的索引结果值不可寻址。 29 | //_ = &(str[0:2]) // 对字符串变量的切片结果值不可寻址。 30 | str2 := str[0] 31 | _ = &str2 // 但这样的寻址就是合法的。 32 | 33 | //_ = &(123 + 456) // 算术操作的结果值不可寻址。 34 | num2 := 456 35 | _ = num2 36 | //_ = &(num + num2) // 算术操作的结果值不可寻址。 37 | 38 | //_ = &([3]int{1, 2, 3}[0]) // 对数组字面量的索引结果值不可寻址。 39 | //_ = &([3]int{1, 2, 3}[0:2]) // 对数组字面量的切片结果值不可寻址。 40 | _ = &([]int{1, 2, 3}[0]) // 对切片字面量的索引结果值却是可寻址的。 41 | //_ = &([]int{1, 2, 3}[0:2]) // 对切片字面量的切片结果值不可寻址。 42 | //_ = &(map[int]string{1: "a"}[0]) // 对字典字面量的索引结果值不可寻址。 43 | 44 | var map1 = map[int]string{1: "a", 2: "b", 3: "c"} 45 | _ = map1 46 | //_ = &(map1[2]) // 对字典变量的索引结果值不可寻址。 47 | 48 | //_ = &(func(x, y int) int { 49 | // return x + y 50 | //}) // 字面量代表的函数不可寻址。 51 | //_ = &(fmt.Sprintf) // 标识符代表的函数不可寻址。 52 | //_ = &(fmt.Sprintln("abc")) // 对函数的调用结果值不可寻址。 53 | 54 | dog := Dog{"little pig"} 55 | _ = dog 56 | //_ = &(dog.Name) // 标识符代表的函数不可寻址。 57 | //_ = &(dog.Name()) // 对方法的调用结果值不可寻址。 58 | 59 | //_ = &(Dog{"little pig"}.name) // 结构体字面量的字段不可寻址。 60 | 61 | //_ = &(interface{}(dog)) // 类型转换表达式的结果值不可寻址。 62 | dogI := interface{}(dog) 63 | _ = dogI 64 | //_ = &(dogI.(Named)) // 类型断言表达式的结果值不可寻址。 65 | named := dogI.(Named) 66 | _ = named 67 | //_ = &(named.(Dog)) // 类型断言表达式的结果值不可寻址。 68 | 69 | var chan1 = make(chan int, 1) 70 | chan1 <- 1 71 | //_ = &(<-chan1) // 接收表达式的结果值不可寻址。 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q1/demo55_test.go: -------------------------------------------------------------------------------- 1 | package q1 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var expectedPrimes = []int{ 8 | 2, 3, 5, 7, 11, 13, 17, 19, 9 | 23, 29, 31, 37, 41, 43, 47, 53, 10 | 59, 61, 67, 71, 73, 79, 83, 89, 11 | 97, 101, 103, 107, 109, 113, 127, 131, 12 | 137, 139, 149, 151, 157, 163, 167, 173, 13 | 179, 181, 191, 193, 197, 199, 211, 223, 14 | 227, 229, 233, 239, 241, 251, 257, 263, 15 | 269, 271, 277, 281, 283, 293, 307, 311, 16 | 313, 317, 331, 337, 347, 349, 353, 359, 17 | 367, 373, 379, 383, 389, 397, 401, 409, 18 | 419, 421, 431, 433, 439, 443, 449, 457, 19 | 461, 463, 467, 479, 487, 491, 499, 503, 20 | 509, 521, 523, 541, 547, 557, 563, 569, 21 | 571, 577, 587, 593, 599, 601, 607, 613, 22 | 617, 619, 631, 641, 643, 647, 653, 659, 23 | 661, 673, 677, 683, 691, 701, 709, 719, 24 | 727, 733, 739, 743, 751, 757, 761, 769, 25 | 773, 787, 797, 809, 811, 821, 823, 827, 26 | 829, 839, 853, 857, 859, 863, 877, 881, 27 | 883, 887, 907, 911, 919, 929, 937, 941, 28 | 947, 953, 967, 971, 977, 983, 991, 997, 29 | } 30 | 31 | func TestGetPrimesWith1000(t *testing.T) { 32 | max := 1000 33 | primes := GetPrimes(max) 34 | for i, prime := range primes { 35 | expectedPrime := expectedPrimes[i] 36 | if prime != expectedPrime { 37 | t.Errorf("%dth prime number %d is not the expected value %d", 38 | i, prime, expectedPrime) 39 | } 40 | } 41 | if t.Failed() == false { 42 | t.Logf("The primes less than %d are all correct.", max) 43 | } 44 | } 45 | 46 | func BenchmarkGetPrimesWith100(b *testing.B) { 47 | for i := 0; i < b.N; i++ { 48 | GetPrimes(100) 49 | } 50 | } 51 | 52 | func BenchmarkGetPrimesWith10000(b *testing.B) { 53 | for i := 0; i < b.N; i++ { 54 | GetPrimes(10000) 55 | } 56 | } 57 | 58 | func BenchmarkGetPrimesWith1000000(b *testing.B) { 59 | for i := 0; i < b.N; i++ { 60 | GetPrimes(1000000) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/puzzlers/article6/q3/demo14.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | // 示例1。 7 | { 8 | type MyString = string 9 | str := "BCD" 10 | myStr1 := MyString(str) 11 | myStr2 := MyString("A" + str) 12 | fmt.Printf("%T(%q) == %T(%q): %v\n", 13 | str, str, myStr1, myStr1, str == myStr1) 14 | fmt.Printf("%T(%q) > %T(%q): %v\n", 15 | str, str, myStr2, myStr2, str > myStr2) 16 | fmt.Printf("Type %T is the same as type %T.\n", myStr1, str) 17 | 18 | strs := []string{"E", "F", "G"} 19 | myStrs := []MyString(strs) 20 | fmt.Printf("A value of type []MyString: %T(%q)\n", 21 | myStrs, myStrs) 22 | fmt.Printf("Type %T is the same as type %T.\n", myStrs, strs) 23 | fmt.Println() 24 | } 25 | // 示例2。 26 | { 27 | type MyString string 28 | str := "BCD" 29 | myStr1 := MyString(str) 30 | myStr2 := MyString("A" + str) 31 | _ = myStr2 32 | //fmt.Printf("%T(%q) == %T(%q): %v\n", 33 | // str, str, myStr1, myStr1, str == myStr1) // 这里的判等不合法,会引发编译错误。 34 | //fmt.Printf("%T(%q) > %T(%q): %v\n", 35 | // str, str, myStr2, myStr2, str > myStr2) // 这里的比较不合法,会引发编译错误。 36 | fmt.Printf("Type %T is different from type %T.\n", myStr1, str) 37 | 38 | strs := []string{"E", "F", "G"} 39 | var myStrs []MyString 40 | //myStrs := []MyString(strs) // 这里的类型转换不合法,会引发编译错误。 41 | //fmt.Printf("A value of type []MyString: %T(%q)\n", 42 | // myStrs, myStrs) 43 | fmt.Printf("Type %T is different from type %T.\n", myStrs, strs) 44 | fmt.Println() 45 | } 46 | // 示例3。 47 | { 48 | type MyString1 = string 49 | type MyString2 string 50 | str := "BCD" 51 | myStr1 := MyString1(str) 52 | myStr2 := MyString2(str) 53 | myStr1 = MyString1(myStr2) 54 | myStr2 = MyString2(myStr1) 55 | 56 | myStr1 = str 57 | //myStr2 = str // 这里的赋值不合法,会引发编译错误。 58 | //myStr1 = myStr2 // 这里的赋值不合法,会引发编译错误。 59 | //myStr2 = myStr1 // 这里的赋值不合法,会引发编译错误。 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang_Puzzlers 2 | 3 | 我在极客时间开设的专栏《Go语言核心36讲》的配套项目,也可以称之为“Go语言谜题”项目。其中几乎包含了此专栏涉及到的所有代码。 4 | 5 | 这个专栏的地址[在这里](https://time.geekbang.org/column/intro/112?code=ti58hl0Fap2y5S-OE0G-O-2CiCtjLT94OxcNaBDzI6k%3D)。本项目中的代码携带的信息相对较少,往往需要配合专栏的内容去看。欢迎大家到“极客时间”订阅我的专栏。 6 | 7 | 欢迎广大的专栏读者和Go语言爱好者们查阅和下载!如果此项目对你有所裨益,还请轻点鼠标、`Star`⭐一下。谢谢! 8 | 9 | ## 项目结构说明 10 | 11 | 项目中会有很多像`article3`这样的代码包。这种代码包下面还会有像`q0`或`q2`这样的子代码包。对于这些代码包的层次和命名是有一套潜在的规则的。如下: 12 | 13 | 1. `article3`是第三篇正文的专属代码包。其他名称相似的代码包含义可类推。 14 | 2. 在每个文章代码包中,都可能会有`q0`、`q1`、`q2`、`q3`这类的子代码包。 15 | 3. 此专栏的主体文章是有固定的结构的。它们一般被分为几个部分: 16 | - 主问题提出之前的部分,也被称为前导部分。 17 | - 主问题部分,是文章主体内容的切入点。 18 | - 扩展问题部分,是切入点的延伸和深入,一般由若干个扩展问题组成,比如:扩展问题1、扩展问题2,等等。 19 | - 总结部分,是对前面的阐述和问题的总结。 20 | - 思考题部分,由一到两个思考题组成。这部分的题目没有答案,仅供大家思考和讨论。 21 | 4. 以上述文章结构为基础,`q0`子包中会包含与前导部分对应的示例代码,`q1`子包中会包含与主问题部分对应的代码,而`q2`子包中会包含与扩展问题部分的扩展问题1对应的代码,以此类推。总结部分和思考题部分一般没有与之对应的代码包。 22 | 23 | 一般只有像`q0`、`q1`、`q2`这样的代码包下才会包含源码文件。若文章的某个部分存在对应的代码则至少会有一个源码文件,并且总会有一个命令源码文件作为示例的入口,也就是示例入口文件。每个示例入口文件都会以`demoX.go`为名,其中的`X`代表序号。所有的示例入口文件的序号都是唯一的,并且从第一个出现的示例入口文件开始以自然数的顺序确定序号。这样做可以统计示例的总数量。 24 | 25 | 欢迎大家与我一起学习Go语言。如果你怀疑或确定本项目的代码有错误,请通过专栏找到我,我们一起讨论。谢谢! 26 | 27 | ## 项目状态更新 28 | 29 | - `2018-11-09`:此专栏在此时已更新到了`39`讲,早已超过了原本约定的`36`讲。不过这还没完,预计它最终会达到`50`讲,并且一直更新到12月初。之后,我仍然会对专栏的内容进行专项增补,比如:补充配图、添加思考题的答案,等等。这些增补也同样都会被及时地更新到专栏的在线版中。这些工作都做完了恐怕要到明年的春节了。所以,专栏的读者们,你们赚到了;)。 30 | - `2018-11-20`:此专栏的全部文章都已经写作完成,历时`4`个多月。专栏文章共计`54`篇,其中的主题文章共`49`篇。 31 | - `2019-01-21`:此专栏的所有配图和思考题简答的原稿都已完成。 32 | - `2019-02-02`:发布“新年彩蛋:完整版思考题答案”。 33 | - `2019-02-18`:此专栏的付费读者已突破`20000`! 34 | - `2019-02-21`:此专栏已基于之前的所有工作进行了全面的升级! 35 | - `2019-05-31`:发布“儿童节彩蛋”:添加[序号映射表](mapping_table.md),对应专栏中文章的序号与源码目录中的序号。 36 | - `2020-05-27`:此专栏的付费读者已突破`25000`! 37 | - `2021-10-24`:此专栏的付费读者已突破`31000`! 38 | 39 | ## 进一步学习交流 40 | 41 | 大家可通过以下几个渠道进一步与我交流,并一起学习: 42 | 43 | - 极客时间App中《Go语言核心36讲》专栏的留言区(我几乎每天都会回复留言区中的问题) 44 | - QQ群:GoHackers(群号:361287127) 45 | - 微信公众号:GoHackers 46 | -------------------------------------------------------------------------------- /src/puzzlers/article23/q3/demo62.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | // mailbox 代表信箱。 11 | // 0代表信箱是空的,1代表信箱是满的。 12 | var mailbox uint8 13 | // lock 代表信箱上的锁。 14 | var lock sync.Mutex 15 | // sendCond 代表专用于发信的条件变量。 16 | sendCond := sync.NewCond(&lock) 17 | // recvCond 代表专用于收信的条件变量。 18 | recvCond := sync.NewCond(&lock) 19 | 20 | // send 代表用于发信的函数。 21 | send := func(id, index int) { 22 | lock.Lock() 23 | for mailbox == 1 { 24 | sendCond.Wait() 25 | } 26 | log.Printf("sender [%d-%d]: the mailbox is empty.", 27 | id, index) 28 | mailbox = 1 29 | log.Printf("sender [%d-%d]: the letter has been sent.", 30 | id, index) 31 | lock.Unlock() 32 | recvCond.Broadcast() 33 | } 34 | 35 | // recv 代表用于收信的函数。 36 | recv := func(id, index int) { 37 | lock.Lock() 38 | for mailbox == 0 { 39 | recvCond.Wait() 40 | } 41 | log.Printf("receiver [%d-%d]: the mailbox is full.", 42 | id, index) 43 | mailbox = 0 44 | log.Printf("receiver [%d-%d]: the letter has been received.", 45 | id, index) 46 | lock.Unlock() 47 | sendCond.Signal() // 确定只会有一个发信的goroutine。 48 | } 49 | 50 | // sign 用于传递演示完成的信号。 51 | sign := make(chan struct{}, 3) 52 | max := 6 53 | go func(id, max int) { // 用于发信。 54 | defer func() { 55 | sign <- struct{}{} 56 | }() 57 | for i := 1; i <= max; i++ { 58 | time.Sleep(time.Millisecond * 500) 59 | send(id, i) 60 | } 61 | }(0, max) 62 | go func(id, max int) { // 用于收信。 63 | defer func() { 64 | sign <- struct{}{} 65 | }() 66 | for j := 1; j <= max; j++ { 67 | time.Sleep(time.Millisecond * 200) 68 | recv(id, j) 69 | } 70 | }(1, max/2) 71 | go func(id, max int) { // 用于收信。 72 | defer func() { 73 | sign <- struct{}{} 74 | }() 75 | for k := 1; k <= max; k++ { 76 | time.Sleep(time.Millisecond * 200) 77 | recv(id, k) 78 | } 79 | }(2, max/2) 80 | 81 | <-sign 82 | <-sign 83 | <-sign 84 | } 85 | -------------------------------------------------------------------------------- /mapping_table.md: -------------------------------------------------------------------------------- 1 | ## 序号映射表 2 | 3 | 由于一些比较长的文章会被极客时间的编辑们拆成多篇,所以专栏中文章的序号与源码目录中的序号并未对齐。因此,我特意创建了下面这张表,以便读者们做对照阅读。 4 | 5 | 6 | | 文章 | 源码目录 | 7 | | :------ | :------ | 8 | | 01 工作区和GOPATH | article1 | 9 | | 02 命令源码文件 | article2 | 10 | | 03 库源码文件 | article3 | 11 | | 04 程序实体的那些事儿(上) | article4 | 12 | | 05 程序实体的那些事儿(中) | article5 | 13 | | 06 程序实体的那些事儿(下) | article6 | 14 | | 07 数组和切片 | article7 | 15 | | 08 container包中的那些容器 | article8 | 16 | | 09 字典的操作和约束 | article9 | 17 | | 10 通道的基本操作 | article10 | 18 | | 11 通道的高级玩法 | article11 | 19 | | 12 使用函数的正确姿势 | article12 | 20 | | 13 结构体及其方法的使用法门 | article13 | 21 | | 14 接口类型的合理运用 | article14 | 22 | | 15 关于指针的有限操作 | article15 | 23 | | 16 go语句及其执行规则(上) | article16 | 24 | | 17 go语句及其执行规则(下) | article16 | 25 | | 18 if语句、for语句和switch语句 | article17 | 26 | | 19 错误处理(上) | article18 | 27 | | 20 错误处理(下) | article18 | 28 | | 21 panic函数、recover函数以及defer语句(上) | article19 | 29 | | 22 panic函数、recover函数以及defer语句(下) | article19 | 30 | | 23 测试的基本规则和流程(上) | article20 | 31 | | 24 测试的基本规则和流程(下) | article20 | 32 | | 25 更多的测试手法 | article21 | 33 | | 26 sync.Mutex与sync.RWMutex | article22 | 34 | | 27 条件变量sync.Cond(上) | article23 | 35 | | 28 条件变量sync.Cond(下) | article23 | 36 | | 29 原子操作(上) | article24 | 37 | | 30 原子操作(下) | article24 | 38 | | 31 sync.WaitGroup和sync.Once | article25 | 39 | | 32 context.Context类型 | article26 | 40 | | 33 临时对象池sync.Pool | article27 | 41 | | 34 并发安全字典sync.Map(上) | article28 | 42 | | 35 并发安全字典sync.Map(下) | article28 | 43 | | 36 unicode与字符编码 | article29 | 44 | | 37 strings包与字符串操作 | article30 | 45 | | 38 bytes包与字节串操作(上) | article31 | 46 | | 39 bytes包与字节串操作(下) | article31 | 47 | | 40 io包中的接口和工具(上) | article32 | 48 | | 41 io包中的接口和工具(下) | article32 | 49 | | 42 bufio包中的数据类型(上) | article33 | 50 | | 43 bufio包中的数据类型(下) | article33 | 51 | | 44 使用os包中的API(上) | article34 | 52 | | 45 使用os包中的API(下) | article34 | 53 | | 46 访问网络服务 | article35 | 54 | | 47 基于HTTP协议的网络服务 | article36 | 55 | | 48 程序性能分析基础(上) | article37 | 56 | | 49 程序性能分析基础(下) | article37 | 57 | -------------------------------------------------------------------------------- /src/puzzlers/article27/q0/demo70.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "sync" 8 | ) 9 | 10 | // bufPool 代表存放数据块缓冲区的临时对象池。 11 | var bufPool sync.Pool 12 | 13 | // Buffer 代表了一个简易的数据块缓冲区的接口。 14 | type Buffer interface { 15 | // Delimiter 用于获取数据块之间的定界符。 16 | Delimiter() byte 17 | // Write 用于写一个数据块。 18 | Write(contents string) (err error) 19 | // Read 用于读一个数据块。 20 | Read() (contents string, err error) 21 | // Free 用于释放当前的缓冲区。 22 | Free() 23 | } 24 | 25 | // myBuffer 代表了数据块缓冲区一种实现。 26 | type myBuffer struct { 27 | buf bytes.Buffer 28 | delimiter byte 29 | } 30 | 31 | func (b *myBuffer) Delimiter() byte { 32 | return b.delimiter 33 | } 34 | 35 | func (b *myBuffer) Write(contents string) (err error) { 36 | if _, err = b.buf.WriteString(contents); err != nil { 37 | return 38 | } 39 | return b.buf.WriteByte(b.delimiter) 40 | } 41 | 42 | func (b *myBuffer) Read() (contents string, err error) { 43 | return b.buf.ReadString(b.delimiter) 44 | } 45 | 46 | func (b *myBuffer) Free() { 47 | bufPool.Put(b) 48 | } 49 | 50 | // delimiter 代表预定义的定界符。 51 | var delimiter = byte('\n') 52 | 53 | func init() { 54 | bufPool = sync.Pool{ 55 | New: func() interface{} { 56 | return &myBuffer{delimiter: delimiter} 57 | }, 58 | } 59 | } 60 | 61 | // GetBuffer 用于获取一个数据块缓冲区。 62 | func GetBuffer() Buffer { 63 | return bufPool.Get().(Buffer) 64 | } 65 | 66 | func main() { 67 | buf := GetBuffer() 68 | defer buf.Free() 69 | buf.Write("A Pool is a set of temporary objects that" + 70 | "may be individually saved and retrieved.") 71 | buf.Write("A Pool is safe for use by multiple goroutines simultaneously.") 72 | buf.Write("A Pool must not be copied after first use.") 73 | 74 | fmt.Println("The data blocks in buffer:") 75 | for { 76 | block, err := buf.Read() 77 | if err != nil { 78 | if err == io.EOF { 79 | break 80 | } 81 | panic(fmt.Errorf("unexpected error: %s", err)) 82 | } 83 | fmt.Print(block) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/puzzlers/article36/q1/demo94.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "net/http" 7 | "strings" 8 | "sync" 9 | "time" 10 | ) 11 | 12 | // domains 包含了我们将要访问的一些网络域名。 13 | // 你可以随意地对它们进行增、删、改, 14 | // 不过这会影响到后面的输出内容。 15 | var domains = []string{ 16 | "google.com", 17 | "google.com.hk", 18 | "google.cn", 19 | "golang.org", 20 | "golang.google.cn", 21 | } 22 | 23 | func main() { 24 | // 你可以改变myTransport中的各个字段的值, 25 | // 并观察后面的输出会有什么不同。 26 | myTransport := &http.Transport{ 27 | Proxy: http.ProxyFromEnvironment, 28 | DialContext: (&net.Dialer{ 29 | Timeout: 15 * time.Second, 30 | KeepAlive: 15 * time.Second, 31 | FallbackDelay: 0, 32 | }).DialContext, 33 | MaxConnsPerHost: 2, 34 | MaxIdleConns: 10, 35 | MaxIdleConnsPerHost: 2, 36 | IdleConnTimeout: 30 * time.Second, 37 | ResponseHeaderTimeout: 0, 38 | ExpectContinueTimeout: 1 * time.Second, 39 | TLSHandshakeTimeout: 10 * time.Second, 40 | } 41 | // 你可以改变myClient中的各个字段的值, 42 | // 并观察后面的输出会有什么不同。 43 | myClient := http.Client{ 44 | Transport: myTransport, 45 | Timeout: 20 * time.Second, 46 | } 47 | 48 | var wg sync.WaitGroup 49 | wg.Add(len(domains)) 50 | for _, domain := range domains { 51 | go func(domain string) { 52 | var logBuf strings.Builder 53 | var diff time.Duration 54 | defer func() { 55 | logBuf.WriteString( 56 | fmt.Sprintf("(elapsed time: %s)\n", diff)) 57 | fmt.Println(logBuf.String()) 58 | wg.Done() 59 | }() 60 | url := "https://" + domain 61 | logBuf.WriteString( 62 | fmt.Sprintf("Send request to %q with method GET ...\n", url)) 63 | t1 := time.Now() 64 | resp, err := myClient.Get(url) 65 | diff = time.Now().Sub(t1) 66 | if err != nil { 67 | logBuf.WriteString( 68 | fmt.Sprintf("request sending error: %v\n", err)) 69 | return 70 | } 71 | defer resp.Body.Close() 72 | line2 := resp.Proto + " " + resp.Status 73 | logBuf.WriteString( 74 | fmt.Sprintf("The first line of response:\n%s\n", line2)) 75 | }(domain) 76 | } 77 | wg.Wait() 78 | } 79 | -------------------------------------------------------------------------------- /src/puzzlers/article35/q1/demo91.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "crypto/tls" 6 | "fmt" 7 | "io" 8 | "net" 9 | "runtime" 10 | ) 11 | 12 | func main() { 13 | network := "tcp" 14 | host := "google.cn" 15 | reqStrTpl := `HEAD / HTTP/1.1 16 | Accept: */* 17 | Accept-Encoding: gzip, deflate 18 | Connection: keep-alive 19 | Host: %s 20 | User-Agent: Dialer/%s 21 | 22 | 23 | 24 | ` 25 | 26 | // 示例1。 27 | network1 := network + "4" 28 | address1 := host + ":80" 29 | fmt.Printf("Dial %q with network %q ...\n", address1, network1) 30 | conn1, err := net.Dial(network1, address1) 31 | if err != nil { 32 | fmt.Printf("dial error: %v\n", err) 33 | return 34 | } 35 | defer conn1.Close() 36 | 37 | reqStr1 := fmt.Sprintf(reqStrTpl, host, runtime.Version()) 38 | fmt.Printf("The request:\n%s\n", reqStr1) 39 | _, err = io.WriteString(conn1, reqStr1) 40 | if err != nil { 41 | fmt.Printf("write error: %v\n", err) 42 | return 43 | } 44 | fmt.Println() 45 | 46 | reader1 := bufio.NewReader(conn1) 47 | line1, err := reader1.ReadString('\n') 48 | if err != nil { 49 | fmt.Printf("read error: %v\n", err) 50 | return 51 | } 52 | fmt.Printf("The first line of response:\n%s\n", line1) 53 | fmt.Println() 54 | 55 | // 示例2。 56 | tlsConf := &tls.Config{ 57 | InsecureSkipVerify: true, 58 | MinVersion: tls.VersionTLS10, 59 | } 60 | network2 := network 61 | address2 := host + ":443" 62 | fmt.Printf("Dial %q with network %q ...\n", address2, network2) 63 | conn2, err := tls.Dial(network2, address2, tlsConf) 64 | if err != nil { 65 | fmt.Printf("dial error: %v\n", err) 66 | return 67 | } 68 | defer conn2.Close() 69 | 70 | reqStr2 := fmt.Sprintf(reqStrTpl, host, runtime.Version()) 71 | fmt.Printf("The request:\n%s\n", reqStr2) 72 | _, err = io.WriteString(conn2, reqStr2) 73 | if err != nil { 74 | fmt.Printf("write error: %v\n", err) 75 | return 76 | } 77 | 78 | reader2 := bufio.NewReader(conn2) 79 | line2, err := reader2.ReadString('\n') 80 | if err != nil { 81 | fmt.Printf("read error: %v\n", err) 82 | return 83 | } 84 | fmt.Printf("The first line of response:\n%s\n", line2) 85 | fmt.Println() 86 | } 87 | -------------------------------------------------------------------------------- /src/puzzlers/article31/q2/demo79.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | // 示例1。 10 | var contents string 11 | buffer1 := bytes.NewBufferString(contents) 12 | fmt.Printf("The length of new buffer with contents %q: %d\n", 13 | contents, buffer1.Len()) 14 | fmt.Printf("The capacity of new buffer with contents %q: %d\n", 15 | contents, buffer1.Cap()) 16 | fmt.Println() 17 | 18 | contents = "12345" 19 | fmt.Printf("Write contents %q ...\n", contents) 20 | buffer1.WriteString(contents) 21 | fmt.Printf("The length of buffer: %d\n", buffer1.Len()) 22 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 23 | fmt.Println() 24 | 25 | contents = "67" 26 | fmt.Printf("Write contents %q ...\n", contents) 27 | buffer1.WriteString(contents) 28 | fmt.Printf("The length of buffer: %d\n", buffer1.Len()) 29 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 30 | fmt.Println() 31 | 32 | contents = "89" 33 | fmt.Printf("Write contents %q ...\n", contents) 34 | buffer1.WriteString(contents) 35 | fmt.Printf("The length of buffer: %d\n", buffer1.Len()) 36 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 37 | fmt.Print("\n\n") 38 | 39 | // 示例2。 40 | contents = "abcdefghijk" 41 | buffer2 := bytes.NewBufferString(contents) 42 | fmt.Printf("The length of new buffer with contents %q: %d\n", 43 | contents, buffer2.Len()) 44 | fmt.Printf("The capacity of new buffer with contents %q: %d\n", 45 | contents, buffer2.Cap()) 46 | fmt.Println() 47 | 48 | n := 10 49 | fmt.Printf("Grow the buffer with %d ...\n", n) 50 | buffer2.Grow(n) 51 | fmt.Printf("The length of buffer: %d\n", buffer2.Len()) 52 | fmt.Printf("The capacity of buffer: %d\n", buffer2.Cap()) 53 | fmt.Print("\n\n") 54 | 55 | // 示例3。 56 | var buffer3 bytes.Buffer 57 | fmt.Printf("The length of new buffer: %d\n", buffer3.Len()) 58 | fmt.Printf("The capacity of new buffer: %d\n", buffer3.Cap()) 59 | fmt.Println() 60 | 61 | contents = "xyz" 62 | fmt.Printf("Write contents %q ...\n", contents) 63 | buffer3.WriteString(contents) 64 | fmt.Printf("The length of buffer: %d\n", buffer3.Len()) 65 | fmt.Printf("The capacity of buffer: %d\n", buffer3.Cap()) 66 | } 67 | -------------------------------------------------------------------------------- /src/puzzlers/article34/q2/demo88.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | type flagDesc struct { 11 | flag int 12 | desc string 13 | } 14 | 15 | func main() { 16 | fileName1 := "something2.txt" 17 | filePath1 := filepath.Join(os.TempDir(), fileName1) 18 | fmt.Printf("The file path: %s\n", filePath1) 19 | fmt.Println() 20 | 21 | // 示例1。 22 | contents0 := "OpenFile is the generalized open call." 23 | flagDescList := []flagDesc{ 24 | { 25 | os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 26 | "os.O_WRONLY|os.O_CREATE|os.O_TRUNC", 27 | }, 28 | { 29 | os.O_WRONLY, 30 | "os.O_WRONLY", 31 | }, 32 | { 33 | os.O_WRONLY | os.O_APPEND, 34 | "os.O_WRONLY|os.O_APPEND", 35 | }, 36 | } 37 | 38 | for i, v := range flagDescList { 39 | fmt.Printf("Open the file with flag %s ...\n", v.desc) 40 | file1a, err := os.OpenFile(filePath1, v.flag, 0666) 41 | if err != nil { 42 | fmt.Printf("error: %v\n", err) 43 | continue 44 | } 45 | fmt.Printf("The file descriptor: %d\n", file1a.Fd()) 46 | 47 | contents1 := fmt.Sprintf("[%d]: %s ", i+1, contents0) 48 | fmt.Printf("Write %q to the file ...\n", contents1) 49 | n, err := file1a.WriteString(contents1) 50 | if err != nil { 51 | fmt.Printf("error: %v\n", err) 52 | continue 53 | } 54 | fmt.Printf("The number of bytes written is %d.\n", n) 55 | 56 | file1b, err := os.Open(filePath1) 57 | fmt.Println("Read bytes from the file ...") 58 | bytes, err := ioutil.ReadAll(file1b) 59 | if err != nil { 60 | fmt.Printf("error: %v\n", err) 61 | continue 62 | } 63 | fmt.Printf("Read(%d): %q\n", len(bytes), bytes) 64 | fmt.Println() 65 | } 66 | 67 | // 示例2。 68 | fmt.Println("Try to create an existing file with flag os.O_TRUNC ...") 69 | file2, err := os.OpenFile(filePath1, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 70 | if err != nil { 71 | fmt.Printf("error: %v\n", err) 72 | return 73 | } 74 | fmt.Printf("The file descriptor: %d\n", file2.Fd()) 75 | 76 | fmt.Println("Try to create an existing file with flag os.O_EXCL ...") 77 | _, err = os.OpenFile(filePath1, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) 78 | fmt.Printf("error: %v\n", err) 79 | } 80 | -------------------------------------------------------------------------------- /src/puzzlers/article33/q3/demo86.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | comment := "Writer implements buffering for an io.Writer object. " + 12 | "If an error occurs writing to a Writer, " + 13 | "no more data will be accepted and all subsequent writes, " + 14 | "and Flush, will return the error. After all data has been written, " + 15 | "the client should call the Flush method to guarantee all data " + 16 | "has been forwarded to the underlying io.Writer." 17 | basicWriter1 := &strings.Builder{} 18 | 19 | size := 300 20 | fmt.Printf("New a buffered writer with size %d ...\n", size) 21 | writer1 := bufio.NewWriterSize(basicWriter1, size) 22 | fmt.Println() 23 | 24 | // 示例1。 25 | begin, end := 0, 53 26 | fmt.Printf("Write %d bytes into the writer ...\n", end-begin) 27 | writer1.WriteString(comment[begin:end]) 28 | fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered()) 29 | fmt.Printf("The number of unused bytes in the buffer: %d\n", 30 | writer1.Available()) 31 | fmt.Println("Flush the buffer in the writer ...") 32 | writer1.Flush() 33 | fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered()) 34 | fmt.Printf("The number of unused bytes in the buffer: %d\n", 35 | writer1.Available()) 36 | fmt.Println() 37 | 38 | // 示例2。 39 | begin, end = 0, 326 40 | fmt.Printf("Write %d bytes into the writer ...\n", end-begin) 41 | writer1.WriteString(comment[begin:end]) 42 | fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered()) 43 | fmt.Printf("The number of unused bytes in the buffer: %d\n", 44 | writer1.Available()) 45 | fmt.Println("Flush the buffer in the writer ...") 46 | writer1.Flush() 47 | fmt.Println() 48 | 49 | // 示例3。 50 | basicWriter2 := &bytes.Buffer{} 51 | fmt.Printf("Reset the writer with a bytes buffer(an implementation of io.ReaderFrom) ...\n") 52 | writer1.Reset(basicWriter2) 53 | reader := strings.NewReader(comment) 54 | fmt.Println("Read data from the reader ...") 55 | writer1.ReadFrom(reader) 56 | fmt.Printf("The number of buffered bytes: %d\n", writer1.Buffered()) 57 | fmt.Printf("The number of unused bytes in the buffer: %d\n", 58 | writer1.Available()) 59 | } 60 | -------------------------------------------------------------------------------- /src/puzzlers/article37/q4/demo99.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "puzzlers/article37/common" 8 | "puzzlers/article37/common/op" 9 | "runtime" 10 | "runtime/pprof" 11 | "time" 12 | ) 13 | 14 | // profileNames 代表概要信息名称的列表。 15 | var profileNames = []string{ 16 | "goroutine", 17 | "heap", 18 | "allocs", 19 | "threadcreate", 20 | "block", 21 | "mutex", 22 | } 23 | 24 | // profileOps 代表为了生成不同的概要信息而准备的负载函数的字典。 25 | var profileOps = map[string]common.OpFunc{ 26 | "goroutine": op.BlockProfile, 27 | "heap": op.MemProfile, 28 | "allocs": op.MemProfile, 29 | "threadcreate": op.BlockProfile, 30 | "block": op.BlockProfile, 31 | "mutex": op.BlockProfile, 32 | } 33 | 34 | // debugOpts 代表debug参数的可选值列表。 35 | var debugOpts = []int{ 36 | 0, 37 | 1, 38 | 2, 39 | } 40 | 41 | func main() { 42 | prepare() 43 | dir, err := createDir() 44 | if err != nil { 45 | fmt.Printf("dir creation error: %v\n", err) 46 | return 47 | } 48 | for _, name := range profileNames { 49 | for _, debug := range debugOpts { 50 | err = genProfile(dir, name, debug) 51 | if err != nil { 52 | return 53 | } 54 | time.Sleep(time.Millisecond) 55 | } 56 | } 57 | } 58 | 59 | func genProfile(dir string, name string, debug int) error { 60 | fmt.Printf("Generate %s profile (debug: %d) ...\n", name, debug) 61 | fileName := fmt.Sprintf("%s_%d.out", name, debug) 62 | f, err := common.CreateFile(dir, fileName) 63 | if err != nil { 64 | fmt.Printf("create error: %v (%s)\n", err, fileName) 65 | return err 66 | } 67 | defer f.Close() 68 | if err = common.Execute(profileOps[name], 10); err != nil { 69 | fmt.Printf("execute error: %v (%s)\n", err, fileName) 70 | return err 71 | } 72 | profile := pprof.Lookup(name) 73 | err = profile.WriteTo(f, debug) 74 | if err != nil { 75 | fmt.Printf("write error: %v (%s)\n", err, fileName) 76 | return err 77 | } 78 | return nil 79 | } 80 | 81 | func createDir() (string, error) { 82 | currDir, err := os.Getwd() 83 | if err != nil { 84 | return "", err 85 | } 86 | path := filepath.Join(currDir, "profiles") 87 | err = os.Mkdir(path, 0766) 88 | if err != nil && !os.IsExist(err) { 89 | return "", err 90 | } 91 | return path, nil 92 | } 93 | 94 | func prepare() { 95 | runtime.MemProfileRate = 8 96 | runtime.SetBlockProfileRate(2) 97 | } 98 | -------------------------------------------------------------------------------- /src/puzzlers/article33/q1/demo84.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | comment := "Package bufio implements buffered I/O. " + 11 | "It wraps an io.Reader or io.Writer object, " + 12 | "creating another object (Reader or Writer) that " + 13 | "also implements the interface but provides buffering and " + 14 | "some help for textual I/O." 15 | basicReader := strings.NewReader(comment) 16 | fmt.Printf("The size of basic reader: %d\n", basicReader.Size()) 17 | fmt.Println() 18 | 19 | // 示例1。 20 | fmt.Println("New a buffered reader ...") 21 | reader1 := bufio.NewReader(basicReader) 22 | fmt.Printf("The default size of buffered reader: %d\n", reader1.Size()) 23 | // 此时reader1的缓冲区还没有被填充。 24 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 25 | fmt.Println() 26 | 27 | // 示例2。 28 | bytes, err := reader1.Peek(7) 29 | if err != nil { 30 | fmt.Printf("error: %v\n", err) 31 | } 32 | fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes) 33 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 34 | fmt.Println() 35 | 36 | // 示例3。 37 | buf1 := make([]byte, 7) 38 | n, err := reader1.Read(buf1) 39 | if err != nil { 40 | fmt.Printf("error: %v\n", err) 41 | } 42 | fmt.Printf("Read contents(%d): %q\n", n, buf1) 43 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 44 | fmt.Println() 45 | 46 | // 示例4。 47 | fmt.Printf("Reset the basic reader (size: %d) ...\n", len(comment)) 48 | basicReader.Reset(comment) 49 | fmt.Printf("Reset the buffered reader (size: %d) ...\n", reader1.Size()) 50 | reader1.Reset(basicReader) 51 | peekNum := len(comment) + 1 52 | fmt.Printf("Peek %d bytes ...\n", peekNum) 53 | bytes, err = reader1.Peek(peekNum) 54 | if err != nil { 55 | fmt.Printf("error: %v\n", err) 56 | } 57 | fmt.Printf("The number of peeked bytes: %d\n", len(bytes)) 58 | fmt.Println() 59 | 60 | // 示例5。 61 | fmt.Printf("Reset the basic reader (size: %d) ...\n", len(comment)) 62 | basicReader.Reset(comment) 63 | size := 300 64 | fmt.Printf("New a buffered reader with size %d ...\n", size) 65 | reader2 := bufio.NewReaderSize(basicReader, size) 66 | peekNum = size + 1 67 | fmt.Printf("Peek %d bytes ...\n", peekNum) 68 | bytes, err = reader2.Peek(peekNum) 69 | if err != nil { 70 | fmt.Printf("error: %v\n", err) 71 | } 72 | fmt.Printf("The number of peeked bytes: %d\n", len(bytes)) 73 | } 74 | -------------------------------------------------------------------------------- /src/puzzlers/article26/q4/demo69.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | type myKey int 10 | 11 | func main() { 12 | keys := []myKey{ 13 | myKey(20), 14 | myKey(30), 15 | myKey(60), 16 | myKey(61), 17 | } 18 | values := []string{ 19 | "value in node2", 20 | "value in node3", 21 | "value in node6", 22 | "value in node6Branch", 23 | } 24 | 25 | rootNode := context.Background() 26 | node1, cancelFunc1 := context.WithCancel(rootNode) 27 | defer cancelFunc1() 28 | 29 | // 示例1。 30 | node2 := context.WithValue(node1, keys[0], values[0]) 31 | node3 := context.WithValue(node2, keys[1], values[1]) 32 | fmt.Printf("The value of the key %v found in the node3: %v\n", 33 | keys[0], node3.Value(keys[0])) 34 | fmt.Printf("The value of the key %v found in the node3: %v\n", 35 | keys[1], node3.Value(keys[1])) 36 | fmt.Printf("The value of the key %v found in the node3: %v\n", 37 | keys[2], node3.Value(keys[2])) 38 | fmt.Println() 39 | 40 | // 示例2。 41 | node4, _ := context.WithCancel(node3) 42 | node5, _ := context.WithTimeout(node4, time.Hour) 43 | fmt.Printf("The value of the key %v found in the node5: %v\n", 44 | keys[0], node5.Value(keys[0])) 45 | fmt.Printf("The value of the key %v found in the node5: %v\n", 46 | keys[1], node5.Value(keys[1])) 47 | fmt.Println() 48 | 49 | // 示例3。 50 | node6 := context.WithValue(node5, keys[2], values[2]) 51 | fmt.Printf("The value of the key %v found in the node6: %v\n", 52 | keys[0], node6.Value(keys[0])) 53 | fmt.Printf("The value of the key %v found in the node6: %v\n", 54 | keys[2], node6.Value(keys[2])) 55 | fmt.Println() 56 | 57 | // 示例4。 58 | node6Branch := context.WithValue(node5, keys[3], values[3]) 59 | fmt.Printf("The value of the key %v found in the node6Branch: %v\n", 60 | keys[1], node6Branch.Value(keys[1])) 61 | fmt.Printf("The value of the key %v found in the node6Branch: %v\n", 62 | keys[2], node6Branch.Value(keys[2])) 63 | fmt.Printf("The value of the key %v found in the node6Branch: %v\n", 64 | keys[3], node6Branch.Value(keys[3])) 65 | fmt.Println() 66 | 67 | // 示例5。 68 | node7, _ := context.WithCancel(node6) 69 | node8, _ := context.WithTimeout(node7, time.Hour) 70 | fmt.Printf("The value of the key %v found in the node8: %v\n", 71 | keys[1], node8.Value(keys[1])) 72 | fmt.Printf("The value of the key %v found in the node8: %v\n", 73 | keys[2], node8.Value(keys[2])) 74 | fmt.Printf("The value of the key %v found in the node8: %v\n", 75 | keys[3], node8.Value(keys[3])) 76 | } 77 | -------------------------------------------------------------------------------- /src/puzzlers/article21/q2/demo56_test.go: -------------------------------------------------------------------------------- 1 | package q2 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var expectedPrimes = []int{ 9 | 2, 3, 5, 7, 11, 13, 17, 19, 10 | 23, 29, 31, 37, 41, 43, 47, 53, 11 | 59, 61, 67, 71, 73, 79, 83, 89, 12 | 97, 101, 103, 107, 109, 113, 127, 131, 13 | 137, 139, 149, 151, 157, 163, 167, 173, 14 | 179, 181, 191, 193, 197, 199, 211, 223, 15 | 227, 229, 233, 239, 241, 251, 257, 263, 16 | 269, 271, 277, 281, 283, 293, 307, 311, 17 | 313, 317, 331, 337, 347, 349, 353, 359, 18 | 367, 373, 379, 383, 389, 397, 401, 409, 19 | 419, 421, 431, 433, 439, 443, 449, 457, 20 | 461, 463, 467, 479, 487, 491, 499, 503, 21 | 509, 521, 523, 541, 547, 557, 563, 569, 22 | 571, 577, 587, 593, 599, 601, 607, 613, 23 | 617, 619, 631, 641, 643, 647, 653, 659, 24 | 661, 673, 677, 683, 691, 701, 709, 719, 25 | 727, 733, 739, 743, 751, 757, 761, 769, 26 | 773, 787, 797, 809, 811, 821, 823, 827, 27 | 829, 839, 853, 857, 859, 863, 877, 881, 28 | 883, 887, 907, 911, 919, 929, 937, 941, 29 | 947, 953, 967, 971, 977, 983, 991, 997, 30 | } 31 | 32 | func TestGetPrimesWithAbnormalParam(t *testing.T) { 33 | t.Parallel() 34 | invalidParams := []int{1, 0, -1, -2, -3} 35 | for _, ip := range invalidParams { 36 | result := GetPrimes(ip) 37 | if result == nil { 38 | t.Errorf("The result is nil, but it should not be.") 39 | } 40 | if len(result) > 0 { 41 | t.Errorf("The result is not empty, but it should be.") 42 | } 43 | } 44 | } 45 | 46 | func TestGetPrimesWith1000(t *testing.T) { 47 | t.Parallel() 48 | max := 1000 49 | primes := GetPrimes(max) 50 | for i, prime := range primes { 51 | expectedPrime := expectedPrimes[i] 52 | if prime != expectedPrime { 53 | t.Errorf("%dth prime number %d is not the expected value %d", 54 | i, prime, expectedPrime) 55 | } 56 | } 57 | if t.Failed() == false { 58 | t.Logf("The primes less than %d are all correct.", max) 59 | } 60 | } 61 | 62 | func TestGetPrimesParallel(t *testing.T) { 63 | for _, max := range []int{1, 2, 3, 4, 5} { 64 | max := max * 200 65 | // 这些子测试会被并发地执行, 66 | // 并且只有它们都执行完毕之后当前的测试函数才会执行完成。 67 | // 当前的测试函数并不会与其他测试函数一起被并发的执行。 68 | t.Run(fmt.Sprintf("TestGetPrimesWith%d", max), 69 | func(t *testing.T) { 70 | t.Parallel() 71 | primes := GetPrimes(max) 72 | err := comparePrimes(primes) 73 | if err != nil { 74 | t.Error(err) 75 | } else { 76 | t.Logf("The primes less than %d are all correct.", max) 77 | } 78 | }) 79 | } 80 | } 81 | 82 | func comparePrimes(primes []int) (err error) { 83 | for i, prime := range primes { 84 | expectedPrime := expectedPrimes[i] 85 | if prime != expectedPrime { 86 | err = fmt.Errorf( 87 | "%dth prime number %d is not the expected value %d", 88 | i, prime, expectedPrime) 89 | break 90 | } 91 | } 92 | return 93 | } 94 | -------------------------------------------------------------------------------- /src/puzzlers/article31/q3/demo80.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | // 示例1。 10 | contents := "ab" 11 | buffer1 := bytes.NewBufferString(contents) 12 | fmt.Printf("The capacity of new buffer with contents %q: %d\n", 13 | contents, buffer1.Cap()) 14 | fmt.Println() 15 | 16 | unreadBytes := buffer1.Bytes() 17 | fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes) 18 | fmt.Println() 19 | 20 | contents = "cdefg" 21 | fmt.Printf("Write contents %q ...\n", contents) 22 | buffer1.WriteString(contents) 23 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 24 | fmt.Println() 25 | 26 | // 只要扩充一下之前拿到的未读字节切片unreadBytes, 27 | // 就可以用它来读取甚至修改buffer中的后续内容。 28 | unreadBytes = unreadBytes[:cap(unreadBytes)] 29 | fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes) 30 | fmt.Println() 31 | 32 | value := byte('X') 33 | fmt.Printf("Set a byte in the unread bytes to %v ...\n", value) 34 | unreadBytes[len(unreadBytes)-2] = value 35 | fmt.Printf("The unread bytes of the buffer: %v\n", buffer1.Bytes()) 36 | fmt.Println() 37 | 38 | // 不过,在buffer的内容容器真正扩容之后就无法这么做了。 39 | contents = "hijklmn" 40 | fmt.Printf("Write contents %q ...\n", contents) 41 | buffer1.WriteString(contents) 42 | fmt.Printf("The capacity of buffer: %d\n", buffer1.Cap()) 43 | fmt.Println() 44 | 45 | unreadBytes = unreadBytes[:cap(unreadBytes)] 46 | fmt.Printf("The unread bytes of the buffer: %v\n", unreadBytes) 47 | fmt.Print("\n\n") 48 | 49 | // 示例2。 50 | // Next方法返回的后续字节切片也存在相同的问题。 51 | contents = "12" 52 | buffer2 := bytes.NewBufferString(contents) 53 | fmt.Printf("The capacity of new buffer with contents %q: %d\n", 54 | contents, buffer2.Cap()) 55 | fmt.Println() 56 | 57 | nextBytes := buffer2.Next(2) 58 | fmt.Printf("The next bytes of the buffer: %v\n", nextBytes) 59 | fmt.Println() 60 | 61 | contents = "34567" 62 | fmt.Printf("Write contents %q ...\n", contents) 63 | buffer2.WriteString(contents) 64 | fmt.Printf("The capacity of buffer: %d\n", buffer2.Cap()) 65 | fmt.Println() 66 | 67 | // 只要扩充一下之前拿到的后续字节切片nextBytes, 68 | // 就可以用它来读取甚至修改buffer中的后续内容。 69 | nextBytes = nextBytes[:cap(nextBytes)] 70 | fmt.Printf("The next bytes of the buffer: %v\n", nextBytes) 71 | fmt.Println() 72 | 73 | value = byte('X') 74 | fmt.Printf("Set a byte in the next bytes to %v ...\n", value) 75 | nextBytes[len(nextBytes)-2] = value 76 | fmt.Printf("The unread bytes of the buffer: %v\n", buffer2.Bytes()) 77 | fmt.Println() 78 | 79 | // 不过,在buffer的内容容器真正扩容之后就无法这么做了。 80 | contents = "89101112" 81 | fmt.Printf("Write contents %q ...\n", contents) 82 | buffer2.WriteString(contents) 83 | fmt.Printf("The capacity of buffer: %d\n", buffer2.Cap()) 84 | fmt.Println() 85 | 86 | nextBytes = nextBytes[:cap(nextBytes)] 87 | fmt.Printf("The next bytes of the buffer: %v\n", nextBytes) 88 | } 89 | -------------------------------------------------------------------------------- /src/puzzlers/article24/q1/demo63.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync/atomic" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | 11 | // 第二个衍生问题的示例。 12 | num := uint32(18) 13 | fmt.Printf("The number: %d\n", num) 14 | delta := int32(-3) 15 | atomic.AddUint32(&num, uint32(delta)) 16 | fmt.Printf("The number: %d\n", num) 17 | atomic.AddUint32(&num, ^uint32(-(-3)-1)) 18 | fmt.Printf("The number: %d\n", num) 19 | 20 | fmt.Printf("The two's complement of %d: %b\n", 21 | delta, uint32(delta)) // -3的补码。 22 | fmt.Printf("The equivalent: %b\n", ^uint32(-(-3)-1)) // 与-3的补码相同。 23 | fmt.Println() 24 | 25 | // 第三个衍生问题的示例。 26 | forAndCAS1() 27 | fmt.Println() 28 | forAndCAS2() 29 | } 30 | 31 | // forAndCAS1 用于展示简易的自旋锁。 32 | func forAndCAS1() { 33 | sign := make(chan struct{}, 2) 34 | num := int32(0) 35 | fmt.Printf("The number: %d\n", num) 36 | go func() { // 定时增加num的值。 37 | defer func() { 38 | sign <- struct{}{} 39 | }() 40 | for { 41 | time.Sleep(time.Millisecond * 500) 42 | newNum := atomic.AddInt32(&num, 2) 43 | fmt.Printf("The number: %d\n", newNum) 44 | if newNum == 10 { 45 | break 46 | } 47 | } 48 | }() 49 | go func() { // 定时检查num的值,如果等于10就将其归零。 50 | defer func() { 51 | sign <- struct{}{} 52 | }() 53 | for { 54 | if atomic.CompareAndSwapInt32(&num, 10, 0) { 55 | fmt.Println("The number has gone to zero.") 56 | break 57 | } 58 | time.Sleep(time.Millisecond * 500) 59 | } 60 | }() 61 | <-sign 62 | <-sign 63 | } 64 | 65 | // forAndCAS2 用于展示一种简易的(且更加宽松的)互斥锁的模拟。 66 | func forAndCAS2() { 67 | sign := make(chan struct{}, 2) 68 | num := int32(0) 69 | fmt.Printf("The number: %d\n", num) 70 | max := int32(20) 71 | go func(id int, max int32) { // 定时增加num的值。 72 | defer func() { 73 | sign <- struct{}{} 74 | }() 75 | for i := 0; ; i++ { 76 | currNum := atomic.LoadInt32(&num) 77 | if currNum >= max { 78 | break 79 | } 80 | newNum := currNum + 2 81 | time.Sleep(time.Millisecond * 200) 82 | if atomic.CompareAndSwapInt32(&num, currNum, newNum) { 83 | fmt.Printf("The number: %d [%d-%d]\n", newNum, id, i) 84 | } else { 85 | fmt.Printf("The CAS operation failed. [%d-%d]\n", id, i) 86 | } 87 | } 88 | }(1, max) 89 | go func(id int, max int32) { // 定时增加num的值。 90 | defer func() { 91 | sign <- struct{}{} 92 | }() 93 | for j := 0; ; j++ { 94 | currNum := atomic.LoadInt32(&num) 95 | if currNum >= max { 96 | break 97 | } 98 | newNum := currNum + 2 99 | time.Sleep(time.Millisecond * 200) 100 | if atomic.CompareAndSwapInt32(&num, currNum, newNum) { 101 | fmt.Printf("The number: %d [%d-%d]\n", newNum, id, j) 102 | } else { 103 | fmt.Printf("The CAS operation failed. [%d-%d]\n", id, j) 104 | } 105 | } 106 | }(2, max) 107 | <-sign 108 | <-sign 109 | } 110 | -------------------------------------------------------------------------------- /src/puzzlers/article18/q1/demo45.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "runtime" 8 | ) 9 | 10 | // underlyingError 会返回已知的操作系统相关错误的潜在错误值。 11 | func underlyingError(err error) error { 12 | switch err := err.(type) { 13 | case *os.PathError: 14 | return err.Err 15 | case *os.LinkError: 16 | return err.Err 17 | case *os.SyscallError: 18 | return err.Err 19 | case *exec.Error: 20 | return err.Err 21 | } 22 | return err 23 | } 24 | 25 | func main() { 26 | // 示例1。 27 | r, w, err := os.Pipe() 28 | if err != nil { 29 | fmt.Printf("unexpected error: %s\n", err) 30 | return 31 | } 32 | // 人为制造 *os.PathError 类型的错误。 33 | r.Close() 34 | _, err = w.Write([]byte("hi")) 35 | uError := underlyingError(err) 36 | fmt.Printf("underlying error: %s (type: %T)\n", 37 | uError, uError) 38 | fmt.Println() 39 | 40 | // 示例2。 41 | paths := []string{ 42 | os.Args[0], // 当前的源码文件或可执行文件。 43 | "/it/must/not/exist", // 肯定不存在的目录。 44 | os.DevNull, // 肯定存在的目录。 45 | } 46 | printError := func(i int, err error) { 47 | if err == nil { 48 | fmt.Println("nil error") 49 | return 50 | } 51 | err = underlyingError(err) 52 | switch err { 53 | case os.ErrClosed: 54 | fmt.Printf("error(closed)[%d]: %s\n", i, err) 55 | case os.ErrInvalid: 56 | fmt.Printf("error(invalid)[%d]: %s\n", i, err) 57 | case os.ErrPermission: 58 | fmt.Printf("error(permission)[%d]: %s\n", i, err) 59 | } 60 | } 61 | var f *os.File 62 | var index int 63 | { 64 | index = 0 65 | f, err = os.Open(paths[index]) 66 | if err != nil { 67 | fmt.Printf("unexpected error: %s\n", err) 68 | return 69 | } 70 | // 人为制造潜在错误为 os.ErrClosed 的错误。 71 | f.Close() 72 | _, err = f.Read([]byte{}) 73 | printError(index, err) 74 | } 75 | { 76 | index = 1 77 | // 人为制造 os.ErrInvalid 错误。 78 | f, _ = os.Open(paths[index]) 79 | _, err = f.Stat() 80 | printError(index, err) 81 | } 82 | { 83 | index = 2 84 | // 人为制造潜在错误为 os.ErrPermission 的错误。 85 | _, err = exec.LookPath(paths[index]) 86 | printError(index, err) 87 | } 88 | if f != nil { 89 | f.Close() 90 | } 91 | fmt.Println() 92 | 93 | // 示例3。 94 | paths2 := []string{ 95 | runtime.GOROOT(), // 当前环境下的Go语言根目录。 96 | "/it/must/not/exist", // 肯定不存在的目录。 97 | os.DevNull, // 肯定存在的目录。 98 | } 99 | printError2 := func(i int, err error) { 100 | if err == nil { 101 | fmt.Println("nil error") 102 | return 103 | } 104 | err = underlyingError(err) 105 | if os.IsExist(err) { 106 | fmt.Printf("error(exist)[%d]: %s\n", i, err) 107 | } else if os.IsNotExist(err) { 108 | fmt.Printf("error(not exist)[%d]: %s\n", i, err) 109 | } else if os.IsPermission(err) { 110 | fmt.Printf("error(permission)[%d]: %s\n", i, err) 111 | } else { 112 | fmt.Printf("error(other)[%d]: %s\n", i, err) 113 | } 114 | } 115 | { 116 | index = 0 117 | err = os.Mkdir(paths2[index], 0700) 118 | printError2(index, err) 119 | } 120 | { 121 | index = 1 122 | f, err = os.Open(paths[index]) 123 | printError2(index, err) 124 | } 125 | { 126 | index = 2 127 | _, err = exec.LookPath(paths[index]) 128 | printError2(index, err) 129 | } 130 | if f != nil { 131 | f.Close() 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/puzzlers/article24/q2/demo64.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "os" 8 | "reflect" 9 | "sync/atomic" 10 | ) 11 | 12 | func main() { 13 | // 示例1。 14 | var box atomic.Value 15 | fmt.Println("Copy box to box2.") 16 | box2 := box // 原子值在真正使用前可以被复制。 17 | v1 := [...]int{1, 2, 3} 18 | fmt.Printf("Store %v to box.\n", v1) 19 | box.Store(v1) 20 | fmt.Printf("The value load from box is %v.\n", box.Load()) 21 | fmt.Printf("The value load from box2 is %v.\n", box2.Load()) 22 | fmt.Println() 23 | 24 | // 示例2。 25 | v2 := "123" 26 | fmt.Printf("Store %q to box2.\n", v2) 27 | box2.Store(v2) // 这里并不会引发panic。 28 | fmt.Printf("The value load from box is %v.\n", box.Load()) 29 | fmt.Printf("The value load from box2 is %q.\n", box2.Load()) 30 | fmt.Println() 31 | 32 | // 示例3。 33 | fmt.Println("Copy box to box3.") 34 | box3 := box // 原子值在真正使用后不应该被复制! 35 | fmt.Printf("The value load from box3 is %v.\n", box3.Load()) 36 | v3 := 123 37 | fmt.Printf("Store %d to box3.\n", v3) 38 | //box3.Store(v3) // 这里会引发一个panic,报告存储值的类型不一致。 39 | _ = box3 40 | fmt.Println() 41 | 42 | // 示例4。 43 | var box4 atomic.Value 44 | v4 := errors.New("something wrong") 45 | fmt.Printf("Store an error with message %q to box4.\n", v4) 46 | box4.Store(v4) 47 | v41 := io.EOF 48 | fmt.Println("Store a value of the same type to box4.") 49 | box4.Store(v41) 50 | v42, ok := interface{}(&os.PathError{}).(error) 51 | if ok { 52 | fmt.Printf("Store a value of type %T that implements error interface to box4.\n", v42) 53 | //box4.Store(v42) // 这里会引发一个panic,报告存储值的类型不一致。 54 | } 55 | fmt.Println() 56 | 57 | // 示例5。 58 | box5, err := NewAtomicValue(v4) 59 | if err != nil { 60 | fmt.Printf("error: %s\n", err) 61 | } 62 | fmt.Printf("The legal type in box5 is %s.\n", box5.TypeOfValue()) 63 | fmt.Println("Store a value of the same type to box5.") 64 | err = box5.Store(v41) 65 | if err != nil { 66 | fmt.Printf("error: %s\n", err) 67 | } 68 | fmt.Printf("Store a value of type %T that implements error interface to box5.\n", v42) 69 | err = box5.Store(v42) 70 | if err != nil { 71 | fmt.Printf("error: %s\n", err) 72 | } 73 | fmt.Println() 74 | 75 | // 示例6。 76 | var box6 atomic.Value 77 | v6 := []int{1, 2, 3} 78 | fmt.Printf("Store %v to box6.\n", v6) 79 | box6.Store(v6) 80 | v6[1] = 4 // 注意,此处的操作不是并发安全的! 81 | fmt.Printf("The value load from box6 is %v.\n", box6.Load()) 82 | // 正确的做法如下。 83 | v6 = []int{1, 2, 3} 84 | store := func(v []int) { 85 | replica := make([]int, len(v)) 86 | copy(replica, v) 87 | box6.Store(replica) 88 | } 89 | fmt.Printf("Store %v to box6.\n", v6) 90 | store(v6) 91 | v6[2] = 5 // 此处的操作是安全的。 92 | fmt.Printf("The value load from box6 is %v.\n", box6.Load()) 93 | } 94 | 95 | type atomicValue struct { 96 | v atomic.Value 97 | t reflect.Type 98 | } 99 | 100 | func NewAtomicValue(example interface{}) (*atomicValue, error) { 101 | if example == nil { 102 | return nil, errors.New("atomic value: nil example") 103 | } 104 | return &atomicValue{ 105 | t: reflect.TypeOf(example), 106 | }, nil 107 | } 108 | 109 | func (av *atomicValue) Store(v interface{}) error { 110 | if v == nil { 111 | return errors.New("atomic value: nil value") 112 | } 113 | t := reflect.TypeOf(v) 114 | if t != av.t { 115 | return fmt.Errorf("atomic value: wrong type: %s", t) 116 | } 117 | av.v.Store(v) 118 | return nil 119 | } 120 | 121 | func (av *atomicValue) Load() interface{} { 122 | return av.v.Load() 123 | } 124 | 125 | func (av *atomicValue) TypeOfValue() reflect.Type { 126 | return av.t 127 | } 128 | -------------------------------------------------------------------------------- /src/puzzlers/article22/q1/demo59.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "log" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | // singleHandler 代表单次处理函数的类型。 14 | type singleHandler func() (data string, n int, err error) 15 | 16 | // handlerConfig 代表处理流程配置的类型。 17 | type handlerConfig struct { 18 | handler singleHandler // 单次处理函数。 19 | goNum int // 需要启用的goroutine的数量。 20 | number int // 单个goroutine中的处理次数。 21 | interval time.Duration // 单个goroutine中的处理间隔时间。 22 | counter int // 数据量计数器,以字节为单位。 23 | counterMu sync.Mutex // 数据量计数器专用的互斥锁。 24 | 25 | } 26 | 27 | // count 会增加计数器的值,并会返回增加后的计数。 28 | func (hc *handlerConfig) count(increment int) int { 29 | hc.counterMu.Lock() 30 | defer hc.counterMu.Unlock() 31 | hc.counter += increment 32 | return hc.counter 33 | } 34 | 35 | func main() { 36 | // mu 代表以下流程要使用的互斥锁。 37 | // 在下面的函数中直接使用即可,不要传递。 38 | var mu sync.Mutex 39 | 40 | // genWriter 代表的是用于生成写入函数的函数。 41 | genWriter := func(writer io.Writer) singleHandler { 42 | return func() (data string, n int, err error) { 43 | // 准备数据。 44 | data = fmt.Sprintf("%s\t", 45 | time.Now().Format(time.StampNano)) 46 | // 写入数据。 47 | mu.Lock() 48 | defer mu.Unlock() 49 | n, err = writer.Write([]byte(data)) 50 | return 51 | } 52 | } 53 | 54 | // genReader 代表的是用于生成读取函数的函数。 55 | genReader := func(reader io.Reader) singleHandler { 56 | return func() (data string, n int, err error) { 57 | buffer, ok := reader.(*bytes.Buffer) 58 | if !ok { 59 | err = errors.New("unsupported reader") 60 | return 61 | } 62 | // 读取数据。 63 | mu.Lock() 64 | defer mu.Unlock() 65 | data, err = buffer.ReadString('\t') 66 | n = len(data) 67 | return 68 | } 69 | } 70 | 71 | // buffer 代表缓冲区。 72 | var buffer bytes.Buffer 73 | 74 | // 数据写入配置。 75 | writingConfig := handlerConfig{ 76 | handler: genWriter(&buffer), 77 | goNum: 5, 78 | number: 4, 79 | interval: time.Millisecond * 100, 80 | } 81 | // 数据读取配置。 82 | readingConfig := handlerConfig{ 83 | handler: genReader(&buffer), 84 | goNum: 10, 85 | number: 2, 86 | interval: time.Millisecond * 100, 87 | } 88 | 89 | // sign 代表信号的通道。 90 | sign := make(chan struct{}, writingConfig.goNum+readingConfig.goNum) 91 | 92 | // 启用多个goroutine对缓冲区进行多次数据写入。 93 | for i := 1; i <= writingConfig.goNum; i++ { 94 | go func(i int) { 95 | defer func() { 96 | sign <- struct{}{} 97 | }() 98 | for j := 1; j <= writingConfig.number; j++ { 99 | time.Sleep(writingConfig.interval) 100 | data, n, err := writingConfig.handler() 101 | if err != nil { 102 | log.Printf("writer [%d-%d]: error: %s", 103 | i, j, err) 104 | continue 105 | } 106 | total := writingConfig.count(n) 107 | log.Printf("writer [%d-%d]: %s (total: %d)", 108 | i, j, data, total) 109 | } 110 | }(i) 111 | } 112 | 113 | // 启用多个goroutine对缓冲区进行多次数据读取。 114 | for i := 1; i <= readingConfig.goNum; i++ { 115 | go func(i int) { 116 | defer func() { 117 | sign <- struct{}{} 118 | }() 119 | for j := 1; j <= readingConfig.number; j++ { 120 | time.Sleep(readingConfig.interval) 121 | var data string 122 | var n int 123 | var err error 124 | for { 125 | data, n, err = readingConfig.handler() 126 | if err == nil || err != io.EOF { 127 | break 128 | } 129 | // 如果读比写快(读时会发生EOF错误),那就等一会儿再读。 130 | time.Sleep(readingConfig.interval) 131 | } 132 | if err != nil { 133 | log.Printf("reader [%d-%d]: error: %s", 134 | i, j, err) 135 | continue 136 | } 137 | total := readingConfig.count(n) 138 | log.Printf("reader [%d-%d]: %s (total: %d)", 139 | i, j, data, total) 140 | } 141 | }(i) 142 | } 143 | 144 | // signNumber 代表需要接收的信号的数量。 145 | signNumber := writingConfig.goNum + readingConfig.goNum 146 | // 等待上面启用的所有goroutine的运行全部结束。 147 | for j := 0; j < signNumber; j++ { 148 | <-sign 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/puzzlers/article34/q1/demo87.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "path/filepath" 9 | "reflect" 10 | "syscall" 11 | ) 12 | 13 | // ioTypes 代表了io代码包中的所有接口的反射类型。 14 | var ioTypes = []reflect.Type{ 15 | reflect.TypeOf((*io.Reader)(nil)).Elem(), 16 | reflect.TypeOf((*io.Writer)(nil)).Elem(), 17 | reflect.TypeOf((*io.Closer)(nil)).Elem(), 18 | 19 | reflect.TypeOf((*io.ByteReader)(nil)).Elem(), 20 | reflect.TypeOf((*io.RuneReader)(nil)).Elem(), 21 | reflect.TypeOf((*io.ReaderAt)(nil)).Elem(), 22 | reflect.TypeOf((*io.Seeker)(nil)).Elem(), 23 | reflect.TypeOf((*io.WriterTo)(nil)).Elem(), 24 | reflect.TypeOf((*io.ByteWriter)(nil)).Elem(), 25 | reflect.TypeOf((*io.WriterAt)(nil)).Elem(), 26 | reflect.TypeOf((*io.ReaderFrom)(nil)).Elem(), 27 | 28 | reflect.TypeOf((*io.ByteScanner)(nil)).Elem(), 29 | reflect.TypeOf((*io.RuneScanner)(nil)).Elem(), 30 | reflect.TypeOf((*io.ReadSeeker)(nil)).Elem(), 31 | reflect.TypeOf((*io.ReadCloser)(nil)).Elem(), 32 | reflect.TypeOf((*io.WriteCloser)(nil)).Elem(), 33 | reflect.TypeOf((*io.WriteSeeker)(nil)).Elem(), 34 | reflect.TypeOf((*io.ReadWriter)(nil)).Elem(), 35 | reflect.TypeOf((*io.ReadWriteSeeker)(nil)).Elem(), 36 | reflect.TypeOf((*io.ReadWriteCloser)(nil)).Elem(), 37 | } 38 | 39 | func main() { 40 | // 示例1。 41 | file1 := (*os.File)(nil) 42 | fileType := reflect.TypeOf(file1) 43 | var buf bytes.Buffer 44 | fmt.Fprintf(&buf, "Type %T implements\n", file1) 45 | for _, t := range ioTypes { 46 | if fileType.Implements(t) { 47 | buf.WriteString(t.String()) 48 | buf.WriteByte(',') 49 | buf.WriteByte('\n') 50 | } 51 | } 52 | output := buf.Bytes() 53 | output[len(output)-2] = '.' 54 | fmt.Printf("%s\n", output) 55 | 56 | // 示例2。 57 | fileName1 := "something1.txt" 58 | filePath1 := filepath.Join(os.TempDir(), fileName1) 59 | var paths []string 60 | paths = append(paths, filePath1) 61 | dir, _ := os.Getwd() 62 | paths = append(paths, filepath.Join(dir[:len(dir)-1], fileName1)) 63 | for _, path := range paths { 64 | fmt.Printf("Create a file with path %s ...\n", path) 65 | _, err := os.Create(path) 66 | if err != nil { 67 | var underlyingErr string 68 | if _, ok := err.(*os.PathError); ok { 69 | underlyingErr = "(path error)" 70 | } 71 | fmt.Printf("error: %v %s\n", err, underlyingErr) 72 | continue 73 | } 74 | fmt.Println("The file has been created.") 75 | } 76 | fmt.Println() 77 | 78 | // 示例3。 79 | fmt.Println("New a file associated with stderr ...") 80 | file3 := os.NewFile(uintptr(syscall.Stderr), "/dev/stderr") 81 | if file3 != nil { 82 | file3.WriteString( 83 | "The Go language program writes something to stderr.\n") 84 | } 85 | fmt.Println() 86 | 87 | // 示例4。 88 | fmt.Printf("Open a file with path %s ...\n", filePath1) 89 | file4, err := os.Open(filePath1) 90 | if err != nil { 91 | fmt.Printf("error: %v\n", err) 92 | return 93 | } 94 | fmt.Println("Write something to the file ...") 95 | _, err = file4.WriteString("something") 96 | var underlyingErr string 97 | if _, ok := err.(*os.PathError); ok { 98 | underlyingErr = "(path error)" 99 | } 100 | fmt.Printf("error: %v %s\n", err, underlyingErr) 101 | fmt.Println() 102 | 103 | // 示例5。 104 | fmt.Printf("Open a file with path %s ...\n", filePath1) 105 | file5a, err := os.Open(filePath1) 106 | if err != nil { 107 | fmt.Printf("error: %v\n", err) 108 | return 109 | } 110 | fmt.Printf( 111 | "Is there only one file descriptor for the same file in the same process? %v\n", 112 | file5a.Fd() == file4.Fd()) 113 | file5b := os.NewFile(file5a.Fd(), filePath1) 114 | fmt.Printf("Can the same file descriptor represent the same file? %v\n", 115 | file5b.Name() == file5a.Name()) 116 | fmt.Println() 117 | 118 | // 示例6。 119 | fmt.Printf("Reuse a file on path %s ...\n", filePath1) 120 | file6, err := os.OpenFile(filePath1, os.O_WRONLY|os.O_TRUNC, 0666) 121 | if err != nil { 122 | fmt.Printf("error: %v\n", err) 123 | return 124 | } 125 | contents := "something" 126 | fmt.Printf("Write %q to the file ...\n", contents) 127 | n, err := file6.WriteString(contents) 128 | if err != nil { 129 | fmt.Printf("error: %v\n", err) 130 | } else { 131 | fmt.Printf("The number of bytes written is %d.\n", n) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/puzzlers/article32/q1/demo82.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "strings" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | comment := "Package io provides basic interfaces to I/O primitives. " + 13 | "Its primary job is to wrap existing implementations of such primitives, " + 14 | "such as those in package os, " + 15 | "into shared public interfaces that abstract the functionality, " + 16 | "plus some other related primitives." 17 | 18 | // 示例1。 19 | fmt.Println("New a string reader and name it \"reader1\" ...") 20 | reader1 := strings.NewReader(comment) 21 | buf1 := make([]byte, 7) 22 | n, err := reader1.Read(buf1) 23 | var offset1, index1 int64 24 | executeIfNoErr(err, func() { 25 | fmt.Printf("Read(%d): %q\n", n, buf1[:n]) 26 | offset1 = int64(53) 27 | index1, err = reader1.Seek(offset1, io.SeekCurrent) 28 | }) 29 | executeIfNoErr(err, func() { 30 | fmt.Printf("The new index after seeking from current with offset %d: %d\n", 31 | offset1, index1) 32 | n, err = reader1.Read(buf1) 33 | }) 34 | executeIfNoErr(err, func() { 35 | fmt.Printf("Read(%d): %q\n", n, buf1[:n]) 36 | }) 37 | fmt.Println() 38 | 39 | // 示例2。 40 | reader1.Reset(comment) 41 | num1 := int64(7) 42 | fmt.Printf("New a limited reader with reader1 and number %d ...\n", num1) 43 | reader2 := io.LimitReader(reader1, 7) 44 | buf2 := make([]byte, 10) 45 | for i := 0; i < 3; i++ { 46 | n, err = reader2.Read(buf2) 47 | executeIfNoErr(err, func() { 48 | fmt.Printf("Read(%d): %q\n", n, buf2[:n]) 49 | }) 50 | } 51 | fmt.Println() 52 | 53 | // 示例3。 54 | reader1.Reset(comment) 55 | offset2 := int64(56) 56 | num2 := int64(72) 57 | fmt.Printf("New a section reader with reader1, offset %d and number %d ...\n", offset2, num2) 58 | reader3 := io.NewSectionReader(reader1, offset2, num2) 59 | buf3 := make([]byte, 20) 60 | for i := 0; i < 5; i++ { 61 | n, err = reader3.Read(buf3) 62 | executeIfNoErr(err, func() { 63 | fmt.Printf("Read(%d): %q\n", n, buf3[:n]) 64 | }) 65 | } 66 | fmt.Println() 67 | 68 | // 示例4。 69 | reader1.Reset(comment) 70 | writer1 := new(strings.Builder) 71 | fmt.Println("New a tee reader with reader1 and writer1 ...") 72 | reader4 := io.TeeReader(reader1, writer1) 73 | buf4 := make([]byte, 40) 74 | for i := 0; i < 8; i++ { 75 | n, err = reader4.Read(buf4) 76 | executeIfNoErr(err, func() { 77 | fmt.Printf("Read(%d): %q\n", n, buf4[:n]) 78 | }) 79 | } 80 | fmt.Println() 81 | 82 | // 示例5。 83 | reader5a := strings.NewReader( 84 | "MultiReader returns a Reader that's the logical concatenation of " + 85 | "the provided input readers.") 86 | reader5b := strings.NewReader("They're read sequentially.") 87 | reader5c := strings.NewReader("Once all inputs have returned EOF, " + 88 | "Read will return EOF.") 89 | reader5d := strings.NewReader("If any of the readers return a non-nil, " + 90 | "non-EOF error, Read will return that error.") 91 | fmt.Println("New a multi-reader with 4 readers ...") 92 | reader5 := io.MultiReader(reader5a, reader5b, reader5c, reader5d) 93 | buf5 := make([]byte, 50) 94 | for i := 0; i < 8; i++ { 95 | n, err = reader5.Read(buf5) 96 | executeIfNoErr(err, func() { 97 | fmt.Printf("Read(%d): %q\n", n, buf5[:n]) 98 | }) 99 | } 100 | fmt.Println() 101 | 102 | // 示例6。 103 | fmt.Println("New a synchronous in-memory pipe ...") 104 | pReader, pWriter := io.Pipe() 105 | _ = interface{}(pReader).(io.ReadCloser) 106 | _ = interface{}(pWriter).(io.WriteCloser) 107 | 108 | comments := [][]byte{ 109 | []byte("Pipe creates a synchronous in-memory pipe."), 110 | []byte("It can be used to connect code expecting an io.Reader "), 111 | []byte("with code expecting an io.Writer."), 112 | } 113 | 114 | // 这里添加这个同步工具纯属为了保证下面示例中的打印语句都能够执行完成。 115 | // 在实际使用中没有必要这样做。 116 | var wg sync.WaitGroup 117 | wg.Add(2) 118 | 119 | go func() { 120 | defer wg.Done() 121 | for _, d := range comments { 122 | time.Sleep(time.Millisecond * 500) 123 | n, err := pWriter.Write(d) 124 | if err != nil { 125 | fmt.Printf("write error: %v\n", err) 126 | break 127 | } 128 | fmt.Printf("Written(%d): %q\n", n, d) 129 | } 130 | pWriter.Close() 131 | }() 132 | go func() { 133 | defer wg.Done() 134 | wBuf := make([]byte, 55) 135 | for { 136 | n, err := pReader.Read(wBuf) 137 | if err != nil { 138 | fmt.Printf("read error: %v\n", err) 139 | break 140 | } 141 | fmt.Printf("Read(%d): %q\n", n, wBuf[:n]) 142 | } 143 | }() 144 | wg.Wait() 145 | } 146 | 147 | func executeIfNoErr(err error, f func()) { 148 | if err != nil { 149 | fmt.Printf("error: %v\n", err) 150 | return 151 | } 152 | f() 153 | } 154 | -------------------------------------------------------------------------------- /src/puzzlers/article28/q0/demo71.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | ) 7 | 8 | // ConcurrentMap 代表自制的简易并发安全字典。 9 | type ConcurrentMap struct { 10 | m map[interface{}]interface{} 11 | mu sync.RWMutex 12 | } 13 | 14 | func NewConcurrentMap() *ConcurrentMap { 15 | return &ConcurrentMap{ 16 | m: make(map[interface{}]interface{}), 17 | } 18 | } 19 | 20 | func (cMap *ConcurrentMap) Delete(key interface{}) { 21 | cMap.mu.Lock() 22 | defer cMap.mu.Unlock() 23 | delete(cMap.m, key) 24 | } 25 | 26 | func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) { 27 | cMap.mu.RLock() 28 | defer cMap.mu.RUnlock() 29 | value, ok = cMap.m[key] 30 | return 31 | } 32 | 33 | func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { 34 | cMap.mu.Lock() 35 | defer cMap.mu.Unlock() 36 | actual, loaded = cMap.m[key] 37 | if loaded { 38 | return 39 | } 40 | cMap.m[key] = value 41 | actual = value 42 | return 43 | } 44 | 45 | func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) { 46 | cMap.mu.RLock() 47 | defer cMap.mu.RUnlock() 48 | for k, v := range cMap.m { 49 | if !f(k, v) { 50 | break 51 | } 52 | } 53 | } 54 | 55 | func (cMap *ConcurrentMap) Store(key, value interface{}) { 56 | cMap.mu.Lock() 57 | defer cMap.mu.Unlock() 58 | cMap.m[key] = value 59 | } 60 | 61 | func main() { 62 | pairs := []struct { 63 | k int 64 | v string 65 | }{ 66 | {k: 1, v: "a"}, 67 | {k: 2, v: "b"}, 68 | {k: 3, v: "c"}, 69 | {k: 4, v: "d"}, 70 | } 71 | 72 | // 示例1。 73 | { 74 | cMap := NewConcurrentMap() 75 | cMap.Store(pairs[0].k, pairs[0].v) 76 | cMap.Store(pairs[1].k, pairs[1].v) 77 | cMap.Store(pairs[2].k, pairs[2].v) 78 | fmt.Println("[Three pairs have been stored in the ConcurrentMap instance]") 79 | 80 | cMap.Range(func(key, value interface{}) bool { 81 | fmt.Printf("The result of an iteration in Range: %v, %v\n", 82 | key, value) 83 | return true 84 | }) 85 | 86 | k0 := pairs[0].k 87 | v0, ok := cMap.Load(k0) 88 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 89 | v0, ok, k0) 90 | 91 | k3 := pairs[3].k 92 | v3, ok := cMap.Load(k3) 93 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 94 | v3, ok, k3) 95 | 96 | k2, v2 := pairs[2].k, pairs[2].v 97 | actual2, loaded2 := cMap.LoadOrStore(k2, v2) 98 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 99 | actual2, loaded2, k2, v2) 100 | v3 = pairs[3].v 101 | actual3, loaded3 := cMap.LoadOrStore(k3, v3) 102 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 103 | actual3, loaded3, k3, v3) 104 | 105 | k1 := pairs[1].k 106 | cMap.Delete(k1) 107 | fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance]\n", 108 | k1) 109 | v1, ok := cMap.Load(k1) 110 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 111 | v1, ok, k1) 112 | v1 = pairs[1].v 113 | actual1, loaded1 := cMap.LoadOrStore(k1, v1) 114 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 115 | actual1, loaded1, k1, v1) 116 | 117 | cMap.Range(func(key, value interface{}) bool { 118 | fmt.Printf("The result of an iteration in Range: %v, %v\n", 119 | key, value) 120 | return true 121 | }) 122 | } 123 | fmt.Println() 124 | 125 | // 示例2。 126 | { 127 | var sMap sync.Map 128 | sMap.Store(pairs[0].k, pairs[0].v) 129 | sMap.Store(pairs[1].k, pairs[1].v) 130 | sMap.Store(pairs[2].k, pairs[2].v) 131 | fmt.Println("[Three pairs have been stored in the sync.Map instance]") 132 | 133 | sMap.Range(func(key, value interface{}) bool { 134 | fmt.Printf("The result of an iteration in Range: %v, %v\n", 135 | key, value) 136 | return true 137 | }) 138 | 139 | k0 := pairs[0].k 140 | v0, ok := sMap.Load(k0) 141 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 142 | v0, ok, k0) 143 | 144 | k3 := pairs[3].k 145 | v3, ok := sMap.Load(k3) 146 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 147 | v3, ok, k3) 148 | 149 | k2, v2 := pairs[2].k, pairs[2].v 150 | actual2, loaded2 := sMap.LoadOrStore(k2, v2) 151 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 152 | actual2, loaded2, k2, v2) 153 | v3 = pairs[3].v 154 | actual3, loaded3 := sMap.LoadOrStore(k3, v3) 155 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 156 | actual3, loaded3, k3, v3) 157 | 158 | k1 := pairs[1].k 159 | sMap.Delete(k1) 160 | fmt.Printf("[The pair with the key of %v has been removed from the sync.Map instance]\n", 161 | k1) 162 | v1, ok := sMap.Load(k1) 163 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 164 | v1, ok, k1) 165 | v1 = pairs[1].v 166 | actual1, loaded1 := sMap.LoadOrStore(k1, v1) 167 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 168 | actual1, loaded1, k1, v1) 169 | 170 | sMap.Range(func(key, value interface{}) bool { 171 | fmt.Printf("The result of an iteration in Range: %v, %v\n", 172 | key, value) 173 | return true 174 | }) 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /src/puzzlers/article33/q2/demo85.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | comment := "Package bufio implements buffered I/O. " + 11 | "It wraps an io.Reader or io.Writer object, " + 12 | "creating another object (Reader or Writer) that " + 13 | "also implements the interface but provides buffering and " + 14 | "some help for textual I/O." 15 | basicReader := strings.NewReader(comment) 16 | fmt.Printf("The size of basic reader: %d\n", basicReader.Size()) 17 | 18 | size := 300 19 | fmt.Printf("New a buffered reader with size %d ...\n", size) 20 | reader1 := bufio.NewReaderSize(basicReader, size) 21 | fmt.Println() 22 | 23 | fmt.Print("[ About 'Peek' method ]\n\n") 24 | // 示例1。 25 | peekNum := 38 26 | fmt.Printf("Peek %d bytes ...\n", peekNum) 27 | bytes, err := reader1.Peek(peekNum) 28 | if err != nil { 29 | fmt.Printf("error: %v\n", err) 30 | } 31 | fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes) 32 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 33 | fmt.Println() 34 | 35 | fmt.Print("[ About 'Read' method ]\n\n") 36 | // 示例2。 37 | readNum := 38 38 | buf1 := make([]byte, readNum) 39 | fmt.Printf("Read %d bytes ...\n", readNum) 40 | n, err := reader1.Read(buf1) 41 | if err != nil { 42 | fmt.Printf("error: %v\n", err) 43 | } 44 | fmt.Printf("Read contents(%d): %q\n", n, buf1) 45 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 46 | fmt.Println() 47 | 48 | fmt.Print("[ About 'ReadSlice' method ]\n\n") 49 | // 示例3。 50 | fmt.Println("Reset the basic reader ...") 51 | basicReader.Reset(comment) 52 | fmt.Println("Reset the buffered reader ...") 53 | reader1.Reset(basicReader) 54 | fmt.Println() 55 | 56 | delimiter := byte('(') 57 | fmt.Printf("Read slice with delimiter %q...\n", delimiter) 58 | line, err := reader1.ReadSlice(delimiter) 59 | if err != nil { 60 | fmt.Printf("error: %v\n", err) 61 | } 62 | fmt.Printf("Read contents(%d): %q\n", len(line), line) 63 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 64 | fmt.Println() 65 | 66 | delimiter = byte('[') 67 | fmt.Printf("Read slice with delimiter %q...\n", delimiter) 68 | line, err = reader1.ReadSlice(delimiter) 69 | if err != nil { 70 | fmt.Printf("error: %v\n", err) 71 | } 72 | fmt.Printf("Read contents(%d): %q\n", len(line), line) 73 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader1.Buffered()) 74 | fmt.Println() 75 | 76 | // 示例4。 77 | fmt.Println("Reset the basic reader ...") 78 | basicReader.Reset(comment) 79 | size = 200 80 | fmt.Printf("New a buffered reader with size %d ...\n", size) 81 | reader2 := bufio.NewReaderSize(basicReader, size) 82 | fmt.Println() 83 | 84 | delimiter = byte('[') 85 | fmt.Printf("Read slice with delimiter %q...\n", delimiter) 86 | line, err = reader2.ReadSlice(delimiter) 87 | if err != nil { 88 | fmt.Printf("error: %v\n", err) 89 | } 90 | fmt.Printf("Read contents(%d): %q\n", len(line), line) 91 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader2.Buffered()) 92 | fmt.Println() 93 | 94 | fmt.Print("[ About 'ReadBytes' method ]\n\n") 95 | // 示例5。 96 | fmt.Println("Reset the basic reader ...") 97 | basicReader.Reset(comment) 98 | size = 200 99 | fmt.Printf("New a buffered reader with size %d ...\n", size) 100 | reader3 := bufio.NewReaderSize(basicReader, size) 101 | fmt.Println() 102 | 103 | delimiter = byte('[') 104 | fmt.Printf("Read bytes with delimiter %q...\n", delimiter) 105 | line, err = reader3.ReadBytes(delimiter) 106 | if err != nil { 107 | fmt.Printf("error: %v\n", err) 108 | } 109 | fmt.Printf("Read contents(%d): %q\n", len(line), line) 110 | fmt.Printf("The number of unread bytes in the buffer: %d\n", reader3.Buffered()) 111 | fmt.Println() 112 | 113 | // 示例6和示例7。 114 | fmt.Print("[ About contents leak ]\n\n") 115 | showContentsLeak(comment) 116 | } 117 | 118 | func showContentsLeak(comment string) { 119 | // 示例6。 120 | basicReader := strings.NewReader(comment) 121 | fmt.Printf("The size of basic reader: %d\n", basicReader.Size()) 122 | 123 | size := len(comment) 124 | fmt.Printf("New a buffered reader with size %d ...\n", size) 125 | reader4 := bufio.NewReaderSize(basicReader, size) 126 | fmt.Println() 127 | 128 | peekNum := 7 129 | fmt.Printf("Peek %d bytes ...\n", peekNum) 130 | bytes, err := reader4.Peek(peekNum) 131 | if err != nil { 132 | fmt.Printf("error: %v\n", err) 133 | } 134 | fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes) 135 | fmt.Println() 136 | 137 | // 只要扩充一下之前拿到的字节切片bytes, 138 | // 就可以用它来读取甚至修改缓冲区中的后续内容。 139 | bytes = bytes[:cap(bytes)] 140 | fmt.Printf("The all of the contents in the buffer:\n%q\n", bytes) 141 | fmt.Println() 142 | 143 | blank := byte(' ') 144 | fmt.Println("Set blanks into the contents in the buffer ...") 145 | for _, i := range []int{55, 56, 57, 58, 66, 67, 68} { 146 | bytes[i] = blank 147 | } 148 | fmt.Println() 149 | 150 | peekNum = size 151 | fmt.Printf("Peek %d bytes ...\n", peekNum) 152 | bytes, err = reader4.Peek(peekNum) 153 | if err != nil { 154 | fmt.Printf("error: %v\n", err) 155 | } 156 | fmt.Printf("Peeked contents(%d):\n%q\n", len(bytes), bytes) 157 | fmt.Println() 158 | 159 | // 示例7。 160 | // ReadSlice方法也存在相同的问题。 161 | delimiter := byte(',') 162 | fmt.Printf("Read slice with delimiter %q...\n", delimiter) 163 | line, err := reader4.ReadSlice(delimiter) 164 | if err != nil { 165 | fmt.Printf("error: %v\n", err) 166 | } 167 | fmt.Printf("Read contents(%d): %q\n", len(line), line) 168 | fmt.Println() 169 | 170 | line = line[:cap(line)] 171 | fmt.Printf("The all of the contents in the buffer:\n%q\n", line) 172 | fmt.Println() 173 | 174 | underline := byte('_') 175 | fmt.Println("Set underlines into the contents in the buffer ...") 176 | for _, i := range []int{89, 92, 103} { 177 | line[i] = underline 178 | } 179 | fmt.Println() 180 | 181 | peekNum = size 182 | fmt.Printf("Peek %d bytes ...\n", peekNum) 183 | bytes, err = reader4.Peek(peekNum) 184 | if err != nil { 185 | fmt.Printf("error: %v\n", err) 186 | } 187 | fmt.Printf("Peeked contents(%d): %q\n", len(bytes), bytes) 188 | } 189 | -------------------------------------------------------------------------------- /src/puzzlers/article28/q2/demo72.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "sync" 8 | ) 9 | 10 | // IntStrMap 代表键类型为int、值类型为string的并发安全字典。 11 | type IntStrMap struct { 12 | m sync.Map 13 | } 14 | 15 | func (iMap *IntStrMap) Delete(key int) { 16 | iMap.m.Delete(key) 17 | } 18 | 19 | func (iMap *IntStrMap) Load(key int) (value string, ok bool) { 20 | v, ok := iMap.m.Load(key) 21 | if v != nil { 22 | value = v.(string) 23 | } 24 | return 25 | } 26 | 27 | func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) { 28 | a, loaded := iMap.m.LoadOrStore(key, value) 29 | actual = a.(string) 30 | return 31 | } 32 | 33 | func (iMap *IntStrMap) Range(f func(key int, value string) bool) { 34 | f1 := func(key, value interface{}) bool { 35 | return f(key.(int), value.(string)) 36 | } 37 | iMap.m.Range(f1) 38 | } 39 | 40 | func (iMap *IntStrMap) Store(key int, value string) { 41 | iMap.m.Store(key, value) 42 | } 43 | 44 | // ConcurrentMap 代表可自定义键类型和值类型的并发安全字典。 45 | type ConcurrentMap struct { 46 | m sync.Map 47 | keyType reflect.Type 48 | valueType reflect.Type 49 | } 50 | 51 | func NewConcurrentMap(keyType, valueType reflect.Type) (*ConcurrentMap, error) { 52 | if keyType == nil { 53 | return nil, errors.New("nil key type") 54 | } 55 | if !keyType.Comparable() { 56 | return nil, fmt.Errorf("incomparable key type: %s", keyType) 57 | } 58 | if valueType == nil { 59 | return nil, errors.New("nil value type") 60 | } 61 | cMap := &ConcurrentMap{ 62 | keyType: keyType, 63 | valueType: valueType, 64 | } 65 | return cMap, nil 66 | } 67 | 68 | func (cMap *ConcurrentMap) Delete(key interface{}) { 69 | if reflect.TypeOf(key) != cMap.keyType { 70 | return 71 | } 72 | cMap.m.Delete(key) 73 | } 74 | 75 | func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) { 76 | if reflect.TypeOf(key) != cMap.keyType { 77 | return 78 | } 79 | return cMap.m.Load(key) 80 | } 81 | 82 | func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { 83 | if reflect.TypeOf(key) != cMap.keyType { 84 | panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key))) 85 | } 86 | if reflect.TypeOf(value) != cMap.valueType { 87 | panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value))) 88 | } 89 | actual, loaded = cMap.m.LoadOrStore(key, value) 90 | return 91 | } 92 | 93 | func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) { 94 | cMap.m.Range(f) 95 | } 96 | 97 | func (cMap *ConcurrentMap) Store(key, value interface{}) { 98 | if reflect.TypeOf(key) != cMap.keyType { 99 | panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key))) 100 | } 101 | if reflect.TypeOf(value) != cMap.valueType { 102 | panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value))) 103 | } 104 | cMap.m.Store(key, value) 105 | } 106 | 107 | // pairs 代表测试用的键值对列表。 108 | var pairs = []struct { 109 | k int 110 | v string 111 | }{ 112 | {k: 1, v: "a"}, 113 | {k: 2, v: "b"}, 114 | {k: 3, v: "c"}, 115 | {k: 4, v: "d"}, 116 | } 117 | 118 | func main() { 119 | // 示例1。 120 | var sMap sync.Map 121 | //sMap.Store([]int{1, 2, 3}, 4) // 这行代码会引发panic。 122 | _ = sMap 123 | 124 | // 示例2。 125 | { 126 | var iMap IntStrMap 127 | iMap.Store(pairs[0].k, pairs[0].v) 128 | iMap.Store(pairs[1].k, pairs[1].v) 129 | iMap.Store(pairs[2].k, pairs[2].v) 130 | fmt.Println("[Three pairs have been stored in the IntStrMap instance]") 131 | 132 | iMap.Range(func(key int, value string) bool { 133 | fmt.Printf("The result of an iteration in Range: %d, %s\n", 134 | key, value) 135 | return true 136 | }) 137 | 138 | k0 := pairs[0].k 139 | v0, ok := iMap.Load(k0) 140 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 141 | v0, ok, k0) 142 | 143 | k3 := pairs[3].k 144 | v3, ok := iMap.Load(k3) 145 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 146 | v3, ok, k3) 147 | 148 | k2, v2 := pairs[2].k, pairs[2].v 149 | actual2, loaded2 := iMap.LoadOrStore(k2, v2) 150 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 151 | actual2, loaded2, k2, v2) 152 | v3 = pairs[3].v 153 | actual3, loaded3 := iMap.LoadOrStore(k3, v3) 154 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 155 | actual3, loaded3, k3, v3) 156 | 157 | k1 := pairs[1].k 158 | iMap.Delete(k1) 159 | fmt.Printf("[The pair with the key of %v has been removed from the IntStrMap instance]\n", 160 | k1) 161 | v1, ok := iMap.Load(k1) 162 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 163 | v1, ok, k1) 164 | v1 = pairs[1].v 165 | actual1, loaded1 := iMap.LoadOrStore(k1, v1) 166 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 167 | actual1, loaded1, k1, v1) 168 | 169 | iMap.Range(func(key int, value string) bool { 170 | fmt.Printf("The result of an iteration in Range: %d, %s\n", 171 | key, value) 172 | return true 173 | }) 174 | } 175 | fmt.Println() 176 | 177 | // 示例2。 178 | { 179 | cMap, err := NewConcurrentMap( 180 | reflect.TypeOf(pairs[0].k), reflect.TypeOf(pairs[0].v)) 181 | if err != nil { 182 | fmt.Printf("fatal error: %s", err) 183 | return 184 | } 185 | cMap.Store(pairs[0].k, pairs[0].v) 186 | cMap.Store(pairs[1].k, pairs[1].v) 187 | cMap.Store(pairs[2].k, pairs[2].v) 188 | fmt.Println("[Three pairs have been stored in the ConcurrentMap instance]") 189 | 190 | cMap.Range(func(key, value interface{}) bool { 191 | fmt.Printf("The result of an iteration in Range: %d, %s\n", 192 | key, value) 193 | return true 194 | }) 195 | 196 | k0 := pairs[0].k 197 | v0, ok := cMap.Load(k0) 198 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 199 | v0, ok, k0) 200 | 201 | k3 := pairs[3].k 202 | v3, ok := cMap.Load(k3) 203 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 204 | v3, ok, k3) 205 | 206 | k2, v2 := pairs[2].k, pairs[2].v 207 | actual2, loaded2 := cMap.LoadOrStore(k2, v2) 208 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 209 | actual2, loaded2, k2, v2) 210 | v3 = pairs[3].v 211 | actual3, loaded3 := cMap.LoadOrStore(k3, v3) 212 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 213 | actual3, loaded3, k3, v3) 214 | 215 | k1 := pairs[1].k 216 | cMap.Delete(k1) 217 | fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance]\n", 218 | k1) 219 | v1, ok := cMap.Load(k1) 220 | fmt.Printf("The result of Load: %v, %v (key: %v)\n", 221 | v1, ok, k1) 222 | v1 = pairs[1].v 223 | actual1, loaded1 := cMap.LoadOrStore(k1, v1) 224 | fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 225 | actual1, loaded1, k1, v1) 226 | 227 | cMap.Range(func(key, value interface{}) bool { 228 | fmt.Printf("The result of an iteration in Range: %d, %s\n", 229 | key, value) 230 | return true 231 | }) 232 | } 233 | } 234 | --------------------------------------------------------------------------------