├── README.md ├── RPC ├── http │ ├── client.go │ └── server.go ├── json │ ├── client.go │ └── server.go └── tcp │ ├── client.go │ └── server.go ├── Tcp-socket ├── server-with-goroutine.go ├── the-client.go └── the-server.go ├── UnmarshalJSON.go ├── actor.go ├── array.go ├── atomic-counters.go ├── base64-encoding.go ├── boring-lines.go ├── boring-quit.go ├── boring.go ├── channel-buffering.go ├── channel-directions.go ├── channel-synchronization.go ├── closing-channels.go ├── closures.go ├── collection-functions.go ├── command-line-arguments.go ├── command-line-flags.go ├── complicated-map.go ├── convertToPNG.go ├── defer.go ├── environment-variables.go ├── epoch.go ├── error.go ├── execing-processes.go ├── exit.go ├── for.go ├── function.go ├── generator_boring.go ├── go-concurrency ├── a-very-simple-timer.go ├── bufio-read.go ├── cache-chan.go ├── cool-channel.go ├── for-array-print.go ├── hashSet.go ├── mutex-example.go ├── select-channel.go ├── single-way-channel.go ├── sync-once.go ├── sync-pool.go ├── timeout-select.go └── wait-group.go ├── go-http.go ├── go-libary ├── image.go ├── net-http │ ├── HiJack.go │ ├── net-http-body.go │ ├── net-http-handle.go │ ├── net-http.go │ ├── net-server.go │ ├── newServeMux.go │ └── test.go ├── parse-ip.go └── try-spider.go ├── go-slice-usage.go ├── go-timeout-moving-on.go ├── gob.go ├── goroutine.go ├── handler-as-middleware.go ├── http-basic-auth.go ├── http-middleware-two.go ├── http-middleware.go ├── if_else.go ├── interface.go ├── json-and-go.go ├── json-array.go ├── json-list.go ├── json.go ├── learning_golang └── src │ ├── algorithm │ ├── fibonacci │ │ └── main.go │ └── gcd │ │ └── main.go │ ├── alice │ ├── power.go │ └── simple.go │ ├── ast │ └── example.go │ ├── bits │ └── hello.go │ ├── bolt │ └── hello.go │ ├── bytes │ ├── reader_buffer.go │ └── write_buffer.go │ ├── cache │ └── memory.go │ ├── call_by_funcname │ └── call_by_funcname.go │ ├── catena │ └── hello.go │ ├── cgo │ ├── callback │ │ └── main.go │ ├── cfunc │ │ └── main.go │ └── simple │ │ ├── main.c │ │ └── main.go │ ├── cipher │ └── crypto │ │ ├── main.go │ │ └── rsa_keypair.go │ ├── curl │ └── main.go │ ├── md5 │ ├── parallel.go │ └── serial.go │ └── shell_build │ ├── build.sh │ └── main.go ├── map.go ├── method.go ├── multipart-file-upload.go ├── multiple-return-values.go ├── multiplexing.go ├── mutex.go ├── non-blocking-channel-operations.go ├── number-parsing.go ├── orange-algorithms-go └── array-simple-to-use.go ├── page_url.txt ├── panic.go ├── ping-pong.go ├── pointer.go ├── pubsub.go ├── random-numbers.go ├── random.go ├── range-over-channels.go ├── range.go ├── rate-limiting.go ├── reading-files.go ├── real-life-concurrency-in-go.go ├── recursion.go ├── regular-expressions.go ├── select.go ├── sha1-hashes.go ├── signals.go ├── simple-web-server.go ├── slice.go ├── sorting-by-functions.go ├── sorting.go ├── spawning-processes.go ├── string-formatting.go ├── string-functions.go ├── sum-goroutines.go ├── switch.go ├── tickers.go ├── time-formatting-parsing.go ├── time_sub.go ├── timeout_boring.go ├── timeouts.go ├── timers.go ├── times.go ├── unix_pipe_channel_note.go ├── url-parsing.go ├── variant-types-in-golang.go ├── wait-group.go ├── websocket.go ├── worker-pools.go └── writing-files.go /README.md: -------------------------------------------------------------------------------- 1 | # go_by_example 2 | 3 | [![Go Report Card](https://goreportcard.com/badge/github.com/josephspurrier/gowebapp)](https://goreportcard.com/report/github.com/josephspurrier/gowebapp) 4 | [![GoDoc](https://godoc.org/github.com/josephspurrier/gowebapp?status.svg)](https://godoc.org/github.com/josephspurrier/gowebapp) 5 | 6 | There are nice Golang code examples here. 7 | 8 | `Go by example` code and some nice programs about Golang 9 | 10 | More than `Go by example` 11 | -------------------------------------------------------------------------------- /RPC/http/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/rpc" 7 | "os" 8 | ) 9 | 10 | type Args struct { 11 | A, B int 12 | } 13 | 14 | type Quotient struct { 15 | Quo, Rem int 16 | } 17 | 18 | func main() { 19 | if len(os.Args) != 2 { 20 | fmt.Println("Usage: ", os.Args[0], "server") 21 | os.Exit(1) 22 | } 23 | serverAddress := os.Args[1] 24 | 25 | client, err := rpc.DialHTTP("tcp", serverAddress+":9090") // 连接服务端rpc 26 | if err != nil { 27 | log.Fatal("dialing: ", err) 28 | } 29 | 30 | // Synchronous call 31 | args := Args{17, 8} 32 | var reply int 33 | err = client.Call("Math.Multiply", args, &reply) // 将参数传入, 调用服务端的方法 34 | if err != nil { 35 | log.Fatal("Math error: ", err) 36 | } 37 | fmt.Println("Math: %d*%d=%d\n", args.A, args.B, reply) 38 | 39 | var quot Quotient 40 | err = client.Call("Math.Divide", args, ") // 将参数传入, 调用服务端的方法 41 | if err != nil { 42 | log.Fatal("Math error: ", err) 43 | } 44 | fmt.Printf("Math: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem) 45 | } 46 | -------------------------------------------------------------------------------- /RPC/http/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | "net/rpc" 8 | ) 9 | 10 | type Args struct { 11 | A, B int 12 | } 13 | 14 | type Quotient struct { 15 | Quo, Rem int 16 | } 17 | 18 | type Math int 19 | 20 | func (t *Math) Multiply(args *Args, reply *int) error { 21 | *reply = args.A * args.B 22 | return nil 23 | } 24 | 25 | func (t *Math) Divide(args *Args, quo *Quotient) error { 26 | if args.B == 0 { 27 | return errors.New(" divide by zero") 28 | } 29 | quo.Quo = args.A / args.B 30 | quo.Rem = args.A % args.B 31 | return nil 32 | } 33 | 34 | func main() { 35 | math := new(Math) 36 | rpc.Register(math) 37 | rpc.HandleHTTP() 38 | 39 | err := http.ListenAndServe(":9090", nil) 40 | if err != nil { 41 | fmt.Println(err.Error()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /RPC/json/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/rpc/jsonrpc" 7 | "os" 8 | ) 9 | 10 | type Args struct { 11 | A, B int 12 | } 13 | 14 | type Quotient struct { 15 | Quo, Rem int 16 | } 17 | 18 | func main() { 19 | if len(os.Args) != 2 { 20 | fmt.Println("Usage: ", os.Args[0], "server:port") 21 | log.Fatal(1) 22 | } 23 | 24 | service := os.Args[1] 25 | 26 | client, err := jsonrpc.Dial("tcp", service) 27 | if err != nil { 28 | log.Fatal("dialing:", err) 29 | } 30 | // Synchronous call 31 | args := Args{17, 8} 32 | var reply int 33 | 34 | err = client.Call("Math.Multiply", args, &reply) 35 | if err != nil { 36 | log.Fatal("Math error:", err) 37 | } 38 | fmt.Printf("Math: %d*%d=%d\n", args.A, args.B, reply) 39 | 40 | var quot Quotient 41 | err = client.Call("Math.Divide", args, ") 42 | if err != nil { 43 | log.Fatal("Math error:", err) 44 | } 45 | fmt.Printf("Math: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem) 46 | } 47 | -------------------------------------------------------------------------------- /RPC/json/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net" 7 | "net/rpc" 8 | "os" 9 | ) 10 | 11 | type Args struct { 12 | A, B int 13 | } 14 | 15 | type Quotient struct { 16 | Quo, Rem int 17 | } 18 | 19 | type Math int 20 | 21 | func (t *Math) Multiply(args *Args, reply *int) error { 22 | *reply = args.A * args.B 23 | return nil 24 | } 25 | 26 | func (t *Math) Divide(args *Args, quo *Quotient) error { 27 | if args.B == 0 { 28 | return errors.New("divide by zero") 29 | } 30 | quo.Quo = args.A / args.B 31 | quo.Rem = args.A % args.B 32 | return nil 33 | } 34 | 35 | func main() { 36 | 37 | math := new(Math) 38 | rpc.Register(math) 39 | 40 | tcpAddr, err := net.ResolveTCPAddr("tcp", ":1234") 41 | if err != nil { 42 | fmt.Println("Fatal error ", err.Error()) 43 | os.Exit(1) 44 | } 45 | 46 | listener, err := net.ListenTCP("tcp", tcpAddr) 47 | if err != nil { 48 | fmt.Println("Fatal error ", err.Error()) 49 | os.Exit(1) 50 | } 51 | 52 | for { 53 | conn, err := listener.Accept() 54 | if err != nil { 55 | continue 56 | } 57 | rpc.ServeConn(conn) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /RPC/tcp/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/rpc" 7 | "os" 8 | ) 9 | 10 | type Args struct { 11 | A, B int 12 | } 13 | 14 | type Quotient struct { 15 | Quo, Rem int 16 | } 17 | 18 | func main() { 19 | if len(os.Args) != 2 { 20 | fmt.Println("Usage: ", os.Args[0], "server:port") 21 | os.Exit(1) 22 | } 23 | service := os.Args[1] 24 | 25 | client, err := rpc.Dial("tcp", service) 26 | if err != nil { 27 | log.Fatal("dialing: ", err) 28 | } 29 | 30 | args := Args{17, 8} 31 | var reply int 32 | err = client.Call("Math.Multiply", args, &reply) 33 | if err != nil { 34 | log.Fatal("Math error: ", err) 35 | } 36 | fmt.Printf("Math: %d*%d=%d\n", args.A, args.B, reply) 37 | 38 | var quot Quotient 39 | err = client.Call("Math.Divide", args, ") 40 | if err != nil { 41 | log.Fatal("Math error:", err) 42 | } 43 | fmt.Printf("Math: %d/%d=%d remainder %d\n", args.A, args.B, quot.Quo, quot.Rem) 44 | } 45 | -------------------------------------------------------------------------------- /RPC/tcp/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net" 7 | "net/rpc" 8 | "os" 9 | ) 10 | 11 | type Args struct { 12 | A, B int 13 | } 14 | 15 | type Quotient struct { 16 | Quo, Rem int 17 | } 18 | 19 | type Math int 20 | 21 | func (t *Math) Multiply(args *Args, reply *int) error { 22 | *reply = args.A * args.B 23 | return nil 24 | } 25 | 26 | func (t *Math) Divide(args *Args, quo *Quotient) error { 27 | if args.B == 0 { 28 | return errors.New("divide by zero") 29 | } 30 | quo.Quo = args.A / args.B 31 | quo.Rem = args.A % args.B 32 | return nil 33 | } 34 | 35 | func main() { 36 | math := new(Math) 37 | rpc.Register(math) 38 | 39 | tcpAddr, err := net.ResolveTCPAddr("tcp", ":9090") 40 | 41 | if err != nil { 42 | fmt.Println("Fatal error ", err.Error()) 43 | os.Exit(1) 44 | } 45 | 46 | listener, err := net.ListenTCP("tcp", tcpAddr) 47 | if err != nil { 48 | fmt.Println("Fatal error ", err.Error()) 49 | os.Exit(1) 50 | } 51 | 52 | for { // for to accept 53 | conn, err := listener.Accept() // accept 54 | fmt.Println("going") 55 | if err != nil { 56 | continue 57 | } 58 | rpc.ServeConn(conn) // then serve conn 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tcp-socket/server-with-goroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | // "time" 8 | ) 9 | 10 | func main() { 11 | service := ":9009" 12 | tcpAddr, err := net.ResolveTCPAddr("tcp4", service) 13 | fmt.Println(tcpAddr) 14 | checkError(err) 15 | listener, err := net.ListenTCP("tcp", tcpAddr) 16 | for { 17 | conn, err := listener.Accept() 18 | fmt.Println(conn) 19 | if err != nil { 20 | continue 21 | } 22 | go handlerClient(conn) 23 | } 24 | } 25 | 26 | func handlerClient(conn net.Conn) { 27 | defer conn.Close() 28 | daytime := "hello kitty" 29 | conn.Write([]byte(daytime)) // don't care about return value 30 | // we're finished with this client 31 | } 32 | 33 | func checkError(err interface{}) { 34 | if err != nil { 35 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err) 36 | os.Exit(1) 37 | } 38 | } 39 | 40 | // 上面的服务我们跑起来之后,他将会一直在那边等待,直到有新的客户端到达,当有新的客户端到达的时候他反馈当前的时间信息。同时我们注意看循环那里,当有错误发生时,直接continue了, 41 | // 而不是退出,因为在我们编写服务器端的时候,当有错误发生的情况下最好是记录错误,然后当前客户端出错直接退出,而不会影响到当前整个的服务。 42 | -------------------------------------------------------------------------------- /Tcp-socket/the-client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | service := ":9009" 12 | tcpAddr, err := net.ResolveTCPAddr("tcp4", service) 13 | checkError(err) 14 | conn, err := net.DialTCP("tcp", nil, tcpAddr) 15 | checkError(err) 16 | _, err = conn.Write([]byte("HEAD / HTTP/1.0\r\n\r\n")) 17 | checkError(err) 18 | result, err := ioutil.ReadAll(conn) 19 | checkError(err) 20 | fmt.Println(string(result)) 21 | os.Exit(0) 22 | } 23 | 24 | func checkError(err interface{}) { 25 | if err != nil { 26 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err) 27 | os.Exit(1) 28 | } 29 | } 30 | 31 | // 通过上面的代码我们可以看出首先我们根据用户的输入通过net.ResolveTCPAddr获取了一个tcpaddr, 32 | // 然后DialTCP获取了一个TCP链接,然后发送请求信息,最后通过ioutil.ReadAll读取全部的服务器反馈信息。 33 | -------------------------------------------------------------------------------- /Tcp-socket/the-server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | // "time" 8 | ) 9 | 10 | func main() { 11 | service := ":9009" 12 | tcpAddr, err := net.ResolveTCPAddr("tcp4", service) 13 | fmt.Println(tcpAddr) 14 | checkError(err) 15 | listener, err := net.ListenTCP("tcp", tcpAddr) 16 | for { 17 | conn, err := listener.Accept() 18 | fmt.Println(conn) 19 | if err != nil { 20 | continue 21 | } 22 | daytime := "hello world" 23 | conn.Write([]byte(daytime)) 24 | conn.Close() 25 | } 26 | } 27 | 28 | func checkError(err interface{}) { 29 | if err != nil { 30 | fmt.Fprintf(os.Stderr, "Fatal error: %s", err) 31 | os.Exit(1) 32 | } 33 | } 34 | 35 | // 上面的服务我们跑起来之后,他将会一直在那边等待,直到有新的客户端到达,当有新的客户端到达的时候他反馈当前的时间信息。同时我们注意看循环那里,当有错误发生时,直接continue了, 36 | // 而不是退出,因为在我们编写服务器端的时候,当有错误发生的情况下最好是记录错误,然后当前客户端出错直接退出,而不会影响到当前整个的服务。 37 | -------------------------------------------------------------------------------- /UnmarshalJSON.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | type IntBool bool 10 | 11 | func (p *IntBool) UnmarshalJSON(b []byte) error { 12 | str := string(b) 13 | switch str { 14 | case "1": 15 | *p = true 16 | case "0": 17 | *p = false 18 | default: 19 | return fmt.Errorf("unexpected bool: %s", str) 20 | } 21 | return nil 22 | } 23 | 24 | func main() { 25 | var account struct { 26 | Gender IntBool `json:"gender"` 27 | } 28 | 29 | err := json.Unmarshal([]byte(`{"gender":1}`), &account) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | log.Println(account.Gender == true) 34 | } 35 | -------------------------------------------------------------------------------- /actor.go: -------------------------------------------------------------------------------- 1 | var c = make(chan bool) 2 | func Actor() { 3 | <-c // 观察者 4 | // doing something 5 | } 6 | 7 | func main() { 8 | go Actor() // 观察者在后台开始准备 9 | c <- true // 通知观察者 10 | } 11 | 12 | // 一个goroutine就是一个actor,通信是通过语言提供的管道完成的。go语言的goroutine是非常轻量级的,又可以充分发挥多核的优势。 13 | // actor模式的核心就在这里,无锁+充分利用多核,actor之间通过消息通信共同工作。 -------------------------------------------------------------------------------- /array.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | var a [6]int 9 | fmt.Println("empty:", a) 10 | 11 | a[3] = 100 12 | fmt.Println("set: ", a) 13 | fmt.Println("len: ", len(a)) 14 | 15 | //b := [5]int{1, 2, 3, 4, 5} 16 | var twoD [2][3]int 17 | for i := 0; i < 2; i++ { 18 | for j := 0; j < 3; j++ { 19 | twoD[i][j] = i + j 20 | } 21 | } 22 | fmt.Println("2d: ", twoD) 23 | } 24 | -------------------------------------------------------------------------------- /atomic-counters.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "sync/atomic" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | var ops uint64 = 0 12 | for i := 0; i < 50; i++ { 13 | go func() { 14 | for { 15 | atomic.AddUint64(&ops, 1) 16 | runtime.Gosched() 17 | } 18 | }() 19 | } 20 | time.Sleep(time.Second) 21 | 22 | opsFinal := atomic.LoadUint64(&ops) 23 | fmt.Println("ops: ", opsFinal) 24 | } 25 | -------------------------------------------------------------------------------- /base64-encoding.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | b64 "encoding/base64" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | data := "abc123!%^*&(*)_+)!@#" 10 | sEnc := b64.StdEncoding.EncodeToString([]byte(data)) 11 | fmt.Println(sEnc) 12 | 13 | sDec, _ := b64.StdEncoding.DecodeString(sEnc) 14 | fmt.Println(string(sDec)) 15 | fmt.Println() 16 | // This encodes/decodes using a URL-compatible base64 format. 17 | uEnc := b64.URLEncoding.EncodeToString([]byte(data)) 18 | fmt.Println(uEnc) 19 | uDec, _ := b64.URLEncoding.DecodeString(uEnc) 20 | fmt.Println(string(uDec)) 21 | } 22 | -------------------------------------------------------------------------------- /boring-lines.go: -------------------------------------------------------------------------------- 1 | func f(left, right chan int) { 2 | left <- 1 + <-right 3 | } 4 | 5 | func main() { 6 | const n = 100000 7 | leftmost := make(chan int) 8 | right := leftmost 9 | left := leftmost 10 | for i := 0; i < n; i++ { 11 | right = make(chan int) 12 | go f(left, right) 13 | left = right 14 | } 15 | go func(c chan int) { c <- 1 }(right) 16 | fmt.Println(<-leftmost) 17 | } -------------------------------------------------------------------------------- /boring-quit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func boring(msg string, quit chan bool) <-chan string { 9 | c := make(chan string) 10 | go func() { 11 | for i := 0; ; i++ { 12 | select { 13 | case c <- fmt.Sprintf("%s: %d", msg, i): 14 | time.Sleep(time.Duration(1000) * time.Millisecond) 15 | case <-quit: 16 | return 17 | } 18 | } 19 | }() 20 | } 21 | 22 | func main() { 23 | quit := make(chan bool) 24 | c := boring("Joe", quit) 25 | for i := 1000; i >= 0; i-- { 26 | fmt.Println(<-c) 27 | } 28 | quit <- true 29 | } 30 | -------------------------------------------------------------------------------- /boring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func boring(msg string, c chan string) { 9 | for i := 0; ; i++ { 10 | c <- fmt.Sprintf("%s %d", msg, i) 11 | time.Sleep(time.Duration(1000) * time.Millisecond) 12 | } 13 | } 14 | 15 | func main() { 16 | c := make(chan string) 17 | go boring("boring", c) 18 | for i := 0; i < 5; i++ { 19 | fmt.Printf("You say: %q\n", <-c) 20 | } 21 | fmt.Println("You're boring; I'm leaving.") 22 | 23 | } 24 | -------------------------------------------------------------------------------- /channel-buffering.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | messages := make(chan string, 2) 9 | 10 | messages <- "buffered" 11 | fmt.Println(<-messages) 12 | messages <- "channel" 13 | messages <- "channel" 14 | 15 | fmt.Println(<-messages) 16 | fmt.Println(<-messages) 17 | } 18 | -------------------------------------------------------------------------------- /channel-directions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // This ping function only accepts a channel for sending values. It would be a compile-time error to try to receive on this channel. 8 | func ping(pings chan<- string, msg string) { 9 | pings <- msg 10 | } 11 | 12 | // The pong function accepts one channel for receives (pings) and a second for sends (pongs). 13 | func pong(pings <-chan string, pongs chan<- string) { 14 | msg := <-pings 15 | pongs <- msg 16 | } 17 | 18 | func main() { 19 | pings := make(chan string, 1) 20 | pongs := make(chan string, 1) 21 | ping(pings, "passed message") 22 | pong(pings, pongs) 23 | fmt.Println(<-pongs) 24 | } 25 | -------------------------------------------------------------------------------- /channel-synchronization.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func worker(done chan bool) { 9 | fmt.Println("working...") 10 | time.Sleep(time.Second) 11 | fmt.Println("done") 12 | done <- true 13 | } 14 | 15 | func main() { 16 | done := make(chan bool, 1) // Start a worker goroutine, giving it the channel to notify on. 17 | 18 | go worker(done) 19 | //Block until we receive a notification from the worker on the channel. 20 | <-done 21 | } 22 | 23 | // This is the function we’ll run in a goroutine. 24 | // The done channel will be used to notify another goroutine that this 25 | // function’s work is done. 26 | // Send a value to notify that we’re done. 27 | 28 | // If you removed the <- done line from this program, 29 | // the program would exit before the worker even started. 30 | -------------------------------------------------------------------------------- /closing-channels.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | jobs := make(chan int, 5) 10 | done := make(chan bool) 11 | go func() { 12 | for { 13 | j, more := <-jobs 14 | if more { 15 | fmt.Println("received job", j) 16 | } else { 17 | fmt.Println("received all jobs") 18 | done <- true // chan 要在不同的goroutine中 19 | return 20 | } 21 | } 22 | }() 23 | 24 | for j := 1; j <= 3; j++ { 25 | jobs <- j 26 | fmt.Println("sent job", j) 27 | time.Sleep(time.Second * 1) 28 | } 29 | //This sends 3 jobs to the worker over the jobs channel, then closes it. 30 | close(jobs) 31 | fmt.Println("sent all jobs") 32 | <-done // chan 要在不同的goroutine中 33 | } 34 | -------------------------------------------------------------------------------- /closures.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func intSeq(a int) func() int { 8 | i := 0 9 | return func() int { 10 | a += 1 11 | i += a + 1 12 | return i 13 | } 14 | } 15 | 16 | func main() { 17 | n := intSeq(2) 18 | fmt.Println(n()) 19 | fmt.Println(n()) //这一次会直接进入到闭包中执行,闭包外的 i:=0 这行代码不会被执行。闭包中的变量结果都会被保留并带入下一个闭包代码执行 20 | fmt.Println(n()) 21 | fmt.Println(n()) 22 | 23 | m := intSeq(2) 24 | fmt.Println(m()) //另一个新的函数开始,和前面那个闭包毫无关系 25 | fmt.Println(n()) 26 | } 27 | -------------------------------------------------------------------------------- /collection-functions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | func Index(vs []string, t string) int { 9 | for i, v := range vs { 10 | if v == t { 11 | return i 12 | } 13 | } 14 | return -1 15 | } 16 | 17 | func Include(vs []string, t string) bool { 18 | return Index(vs, t) >= 0 19 | } 20 | 21 | func Any(vs []string, f func(string) bool) bool { 22 | for _, v := range vs { 23 | if f(v) { 24 | return true 25 | } 26 | } 27 | return false 28 | } 29 | 30 | func All(vs []string, f func(string) bool) bool { 31 | for _, v := range vs { 32 | if !f(v) { 33 | return false 34 | } 35 | } 36 | return true 37 | } 38 | 39 | func Filter(vs []string, f func(string) bool) []string { 40 | vsf := make([]string, 0) 41 | for _, v := range vs { 42 | if f(v) { 43 | vsf = append(vsf, v) 44 | } 45 | } 46 | return vsf 47 | } 48 | 49 | func Map(vs []string, f func(string) string) []string { 50 | vsm := make([]string, len(vs)) 51 | for i, v := range vs { 52 | vsm[i] = f(v) 53 | } 54 | return vsm 55 | } 56 | 57 | func main() { 58 | var strs = []string{"peach", "apple", "pear", "plum"} 59 | fmt.Println(Index(strs, "pear")) 60 | fmt.Println(Include(strs, "grape")) 61 | fmt.Println(Any(strs, func(v string) bool { 62 | return strings.HasPrefix(v, "p") 63 | })) 64 | fmt.Println(All(strs, func(v string) bool { 65 | return strings.HasPrefix(v, "p") 66 | })) 67 | fmt.Println(Filter(strs, func(v string) bool { 68 | return strings.Contains(v, "e") 69 | })) 70 | 71 | fmt.Println(Map(strs, strings.ToUpper)) 72 | } 73 | -------------------------------------------------------------------------------- /command-line-arguments.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "fmt" 5 | 6 | func main() { 7 | // os.Args provides access to raw command-line arguments. Note that the first value in this slice is the path to the program, and os.Args[1:] holds the arguments to the program. 8 | argsWithProg := os.Args 9 | argsWithoutProg := os.Args[1:] 10 | // You can get individual args with normal indexing. 11 | arg := os.Args[3] 12 | fmt.Println(argsWithProg) 13 | fmt.Println(argsWithoutProg) 14 | fmt.Println(arg) 15 | } 16 | -------------------------------------------------------------------------------- /command-line-flags.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Go provides a flag package supporting basic command-line flag parsing. We’ll use this package to implement our example command-line program. 4 | import "flag" 5 | import "fmt" 6 | 7 | func main() { 8 | // Basic flag declarations are available for string, integer, and boolean options. Here we declare a string flag word with a default value "foo" and a short description. This flag.String function returns a string pointer (not a string value); we’ll see how to use this pointer below. 9 | wordPtr := flag.String("word", "foo", "a string") 10 | // This declares numb and fork flags, using a similar approach to the word flag. 11 | numbPtr := flag.Int("numb", 42, "an int") 12 | boolPtr := flag.Bool("fork", false, "a bool") 13 | // It’s also possible to declare an option that uses an existing var declared elsewhere in the program. Note that we need to pass in a pointer to the flag declaration function. 14 | var svar string 15 | flag.StringVar(&svar, "svar", "bar", "a string var") 16 | // Once all flags are declared, call flag.Parse() to execute the command-line parsing. 17 | flag.Parse() 18 | // Here we’ll just dump out the parsed options and any trailing positional arguments. Note that we need to dereference the pointers with e.g. *wordPtr to get the actual option values. 19 | fmt.Println("word:", *wordPtr) 20 | fmt.Println("numb:", *numbPtr) 21 | fmt.Println("fork:", *boolPtr) 22 | fmt.Println("svar:", svar) 23 | fmt.Println("tail:", flag.Args()) 24 | } 25 | -------------------------------------------------------------------------------- /complicated-map.go: -------------------------------------------------------------------------------- 1 | commits := map[string]int{ 2 | "rsc": 3771, 3 | "huhu": 5688, 4 | "gri": 987, 5 | "adhy": 4529, 6 | } 7 | 8 | m = map[string]int{} 9 | 10 | 11 | // For instance, a map of boolean values can be used as a set-like data structure (recall that the zero value for the boolean type is false). 12 | // This example traverses a linked list of Nodes and prints their values. It uses a map of Node pointers to detect cycles in the list. 13 | 14 | 15 | type Node struct { 16 | Next *Node 17 | Value interface{} 18 | } 19 | 20 | var first *Node 21 | 22 | visited := make(map[*Node]bool) 23 | for n := first; n != nil; n = n.Next { 24 | if visited[n] { 25 | fmt.Println("cycle detected") 26 | break 27 | } 28 | visited[n] = true 29 | fmt.Println(n.Value) 30 | } 31 | 32 | type Person struct { 33 | Name string 34 | Likes []string 35 | } 36 | 37 | var people []*Person 38 | 39 | likes := make(map[string][]*Person) 40 | for _,p := range people { 41 | for _, l := range p.Likes { 42 | likes[l] = append(likes[l], p) 43 | } 44 | } 45 | 46 | // To print a list of people who like cheese: 47 | 48 | for _, p := range likes["cheese"] { 49 | fmt.Println(p.Name, "likes cheese.") 50 | } 51 | // To print the number of people who like bacon: 52 | 53 | fmt.Println(len(likes["bacon"]), "people like bacon.") 54 | 55 | hits := make(map[string]map[string]int) 56 | 57 | // This is map of string to (map of string to int). Each key of the outer map is the path to a web page with its own inner map. 58 | // Each inner map key is a two-letter country code. This expression retrieves the number of times an Australian has loaded the documentation page: 59 | n := hits["/doc/"]["au"] 60 | 61 | func add(m map[string]map[string]int, path, country string){ 62 | mm, ok := m[path] 63 | if !ok { 64 | mm = make(map[string]int) 65 | m[path] = mm 66 | } 67 | mm[country]++ 68 | } 69 | add(hist, "/doc/", "au") 70 | 71 | 72 | -------------------------------------------------------------------------------- /convertToPNG.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "code.google.com/p/vp8-go/webp" 5 | "image" 6 | _ "image/jpeg" 7 | "image/png" 8 | "io" 9 | ) 10 | 11 | func convertToPNG(w io.Writer, r io.Reader) error { 12 | img, _, err := image.Decode(r) 13 | if err != nil { 14 | return err 15 | } 16 | return png.Encode(w, img) 17 | } 18 | 19 | func convertJPEGToPNG(w io.Writer, r io.Reader) error { 20 | img, _, err := jpeg.Decode(r) 21 | if err != nil { 22 | return err 23 | } 24 | return png.Encode(w, img) 25 | } 26 | -------------------------------------------------------------------------------- /defer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | f := createFile("/tmp/defer.txt") 10 | defer closeFile(f) 11 | writeFile(f) 12 | } 13 | 14 | func createFile(p string) *os.File { 15 | fmt.Println("Creating") 16 | f, err := os.Create(p) 17 | if err != nil { 18 | panic(err) 19 | } 20 | return f 21 | } 22 | 23 | func writeFile(f *os.File) { 24 | fmt.Println("Writing") 25 | fmt.Fprintln(f, "data") 26 | } 27 | 28 | func closeFile(f *os.File) { 29 | fmt.Println("Closing") 30 | f.Close() 31 | } 32 | -------------------------------------------------------------------------------- /environment-variables.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | func main() { 10 | os.Setenv("FOO", "1") 11 | fmt.Println("FOO: ", os.Getenv("FOO")) 12 | fmt.Println("BAR: ", os.Getenv("BAR")) 13 | 14 | fmt.Println() 15 | for _, e := range os.Environ() { 16 | pair := strings.Split(e, "=") 17 | fmt.Println(pair[0]) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /epoch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | // Use time.Now with Unix or UnixNano to get elapsed time since the Unix epoch in seconds or nanoseconds, respectively. 10 | now := time.Now() 11 | secs := now.Unix() 12 | nanos := now.UnixNano() 13 | fmt.Println(now) 14 | // Note that there is no UnixMillis, so to get the milliseconds since epoch you’ll need to manually divide from nanoseconds. 15 | millis := nanos / 1000000 16 | fmt.Println(secs) 17 | fmt.Println(millis) 18 | fmt.Println(nanos) 19 | // You can also convert integer seconds or nanoseconds since the epoch into the corresponding time. 20 | fmt.Println(time.Unix(secs, 0)) 21 | fmt.Println(time.Unix(0, nanos)) 22 | } 23 | 24 | // 2012-10-31 16:13:58.292387 +0000 UTC 25 | // 1351700038 26 | // 1351700038292 27 | // 1351700038292387000 28 | // 2012-10-31 16:13:58 +0000 UTC 29 | // 2012-10-31 16:13:58.292387 +0000 UTC 30 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | func f1(arg int) (int, error) { 9 | if arg == 42 { 10 | return -1, errors.New("can't work with 42") 11 | } 12 | return arg + 3, nil 13 | } 14 | 15 | type argError struct { 16 | arg int 17 | prob string 18 | } 19 | 20 | func (e *argError) Error() string { 21 | return fmt.Sprintf("%d - %s ", e.arg, e.prob) 22 | } 23 | 24 | func f2(arg int) (int, error) { 25 | if arg == 42 { 26 | return -1, &argError{arg, "can't work with it"} 27 | } 28 | return arg + 3, nil 29 | } 30 | 31 | func main() { 32 | for _, i := range []int{7, 42} { 33 | if r, e := f1(i); e != nil { 34 | fmt.Println("f1 failed:", e) 35 | } else { 36 | fmt.Println("f1 worked:", r) 37 | } 38 | } 39 | for _, i := range []int{7, 42} { 40 | if r, e := f2(i); e != nil { 41 | fmt.Println("f2 failed:", e) 42 | } else { 43 | fmt.Println("f2 worked:", r) 44 | } 45 | } 46 | _, e := f2(42) 47 | if ae, ok := e.(*argError); ok { 48 | fmt.Println(ae.arg) 49 | fmt.Println(ae.prob) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /execing-processes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "syscall" 4 | import "os" 5 | import "os/exec" 6 | 7 | func main() { 8 | // For our example we’ll exec ls. Go requires an absolute path to the binary we want to execute, so we’ll use exec.LookPath to find it (probably /bin/ls). 9 | binary, lookErr := exec.LookPath("ls") 10 | if lookErr != nil { 11 | panic(lookErr) 12 | } 13 | // Exec requires arguments in slice form (as apposed to one big string). We’ll give ls a few common arguments. Note that the first argument should be the program name. 14 | args := []string{"ls", "-a", "-l", "-h"} 15 | // Exec also needs a set of environment variables to use. Here we just provide our current environment. 16 | env := os.Environ() 17 | // Here’s the actual syscall.Exec call. If this call is successful, the execution of our process will end here and be replaced by the /bin/ls -a -l -h process. If there is an error we’ll get a return value. 18 | execErr := syscall.Exec(binary, args, env) 19 | if execErr != nil { 20 | panic(execErr) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /exit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "os" 5 | 6 | func main() { 7 | // defers will not be run when using os.Exit, so this fmt.Println will never be called. 8 | defer fmt.Println("!") 9 | // Exit with status 3. 10 | os.Exit(3) 11 | } 12 | -------------------------------------------------------------------------------- /for.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | i := 1 7 | for i <= 3 { 8 | fmt.Println(i) 9 | i = i + 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /function.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func plus(a int, b int) int { 8 | return a + b 9 | } 10 | func main() { 11 | res := plus(1, 2) 12 | fmt.Println("1+2 = ", res) 13 | } 14 | -------------------------------------------------------------------------------- /generator_boring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func boring(msg string) <-chan string { 9 | c := make(chan string) 10 | go func() { 11 | for i := 0; ; i++ { 12 | c <- fmt.Sprintf("%s %d", msg, i) 13 | time.Sleep(time.Duration(1000) * time.Millisecond) 14 | } 15 | }() 16 | return c 17 | } 18 | 19 | func main() { 20 | joe := boring("Joe") 21 | ann := boring("Ann") 22 | for i := 0; i < 10; i++ { 23 | fmt.Printf("You say: %q\n", <-joe) 24 | fmt.Printf("You say: %q\n", <-ann) 25 | } 26 | fmt.Println("You're boring; I'm leaving.") 27 | } 28 | -------------------------------------------------------------------------------- /go-concurrency/a-very-simple-timer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | // go func(){ 10 | // var timer *time.Timer 11 | // for { 12 | // // 省略若干语句 13 | // case <-func() <-chan time.Timer{ 14 | // if timer == nil { 15 | // timer = time.NewTimer(time.Millisecond) 16 | // }else{ 17 | // timer.Reset(time.Millisecond) 18 | // } 19 | // return time.C 20 | // }(): 21 | // fmt.Println("Timeout.") 22 | // ok = false 23 | // break 24 | // } 25 | // }() 26 | 27 | var t *time.Timer 28 | f := func() { 29 | fmt.Printf("Expiration time: %v\n", time.Now()) 30 | fmt.Printf("C's len: %d\n", len(t.C)) 31 | } 32 | t = time.AfterFunc(1*time.Second, f) // 异步的方式在到期事件来临的那一刻执行定义的函数。不是阻塞的 33 | time.Sleep(2 * time.Second) 34 | } 35 | -------------------------------------------------------------------------------- /go-concurrency/bufio-read.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "bufio" 5 | import "os/exec" 6 | 7 | func main() { 8 | cmd0 := exec.Command("echo", "-n", "My first command from golang") 9 | stdout0, err := cmd0.StdoutPipe() 10 | if err != nil { 11 | fmt.Printf("Error: The command No.0 can not be startup: %s\n", err) 12 | return 13 | } 14 | outputBuf0 := bufio.NewReader(stdout0) 15 | output0, _, err := outputBuf0.ReadLine() 16 | if err != nil { 17 | fmt.Printf("Error: Can not read data the pipe: %s\n", err) 18 | return 19 | } 20 | fmt.Printf("%s\n", string(output0)) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /go-concurrency/cache-chan.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | // func main() { 9 | // unbufChan := make(chan int) 10 | // go func() { 11 | // fmt.Println("Sleep a second...") 12 | // time.Sleep(time.Second) 13 | // num := <-unbufChan 14 | // fmt.Printf("Received a integer %d \n", num) 15 | // }() 16 | 17 | // num := 1 18 | // fmt.Printf("Send integer %d...\n", num) 19 | // unbufChan <- num 20 | // fmt.Println("Done.") 21 | // } 22 | 23 | // Send integer 1... 24 | // Sleep a second... 25 | // Received a integer 1 26 | // Done. 27 | 28 | func main() { 29 | bufChan := make(chan int, 1) 30 | go func() { 31 | fmt.Println("Sleep a second...") 32 | time.Sleep(time.Second) 33 | num := <-bufChan 34 | fmt.Printf("Received a integer %d \n", num) 35 | }() 36 | 37 | num := 1 38 | fmt.Printf("Send integer %d...\n", num) 39 | bufChan <- num 40 | fmt.Println("Done.") 41 | l := len(bufChan) 42 | fmt.Println(l) 43 | } 44 | 45 | // Send integer 1... 46 | // Done. 47 | // 1 48 | // 说明buffer channel 不会阻塞(是异步的),主GOroutine执行速度比go func 的GOroutine快,没有等其执行到,就继续往下 49 | // 执行并结束了。l 的值为1 说明在 bufChan中有一个chan还没没执行完 50 | -------------------------------------------------------------------------------- /go-concurrency/cool-channel.go: -------------------------------------------------------------------------------- 1 | // 不合时宜地关闭一个通道可能会给针对它的发送操作和接收操作带来问题。这样可能会对它们所在的GOroutine的正常流程的执行 2 | // 产生影响。因此,我们应该保证安全的情况下进行关闭通道操作。无论怎样都不应该在接收端关闭通道。因为在那里我们无法判断发送端 3 | // 是否还会向该通道发送元素值。如果非要这样做,那么久应该使用一些辅助手段来避免发送端引发运行时恐慌。 4 | // 然而,我们在发送到调用close以关闭通道却不会对接收该通道中已有的元素值产生任何影响。 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "time" 11 | ) 12 | 13 | func main() { 14 | ch := make(chan int, 5) // ch := make(chan int) It works 15 | sign := make(chan byte) 16 | go func() { 17 | for i := 0; i < 5; i++ { 18 | ch <- i 19 | time.Sleep(1 * time.Second) 20 | } 21 | close(ch) 22 | fmt.Println("The channel is closed.") 23 | sign <- 0 24 | }() 25 | 26 | go func() { 27 | for { 28 | e, ok := <-ch 29 | fmt.Printf("%d (%v)\n", e, ok) 30 | if !ok { 31 | break 32 | } 33 | time.Sleep(2 * time.Second) 34 | } 35 | fmt.Println("Done...") 36 | sign <- 1 37 | }() 38 | <-sign 39 | <-sign 40 | } 41 | 42 | // 我们分别启用了两个GOroutine来对通道进行发送操作和接收操作。发送操作共有5次,每次操作的间隔是1秒。 43 | // 在所有发送操作都完成之后,我们会立即关闭该通道。另一方面,接收操作会持续地进行,每次操作的间隔是2秒。 44 | // 在通过接收语句中的第二个被赋值的变量得知该通道已被关闭之后,我们会结束包含它的for循环,并打印Done。上述 45 | // 发送操作和接收操作的不同间隔的意义在于,接收端在没有将通道中已有的元素全部接收完毕之前,该通道就会被关闭。 46 | 47 | // 很明显,运行时系统并没有在通道ch被关闭之后立即把false作为相应接收操作的第二个结果,而是等到接收端把已在通道 48 | // 中的所有元素都接收到之后才这样做。这确保了在发送端关闭通道的安全性。 49 | // 由此,更确切地讲,调用close函数的作用是告诉运行时系统不应该再允许任何针对被关闭的通道的“发送”操作,该通道即将被关闭。 50 | // 虽然我们调用close函数只是让相应的通道进入关闭状态而不是立即阻止对它的一切操作。但是为了简化概念我们仍然笼统地称在 51 | // 对close函数的调用返回之后该通道就已经被关闭了。不过,读者应该将这其中的真正含义铭记于心。 52 | -------------------------------------------------------------------------------- /go-concurrency/for-array-print.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | names := []string{"Kitty", "Slice", "Namao"} 10 | for _, name := range names { 11 | go func() { 12 | fmt.Printf("Hello %s\n", name) 13 | }() 14 | runtime.Gosched() // for goroutine is wait for the go func goroutine 15 | } 16 | // runtime.Gosched() the result is: all is "Hello Namao" because for code is faster then go func() 17 | } 18 | -------------------------------------------------------------------------------- /go-concurrency/hashSet.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type HashSet struct { 8 | m map[interface{}]bool 9 | } 10 | 11 | func (set *HashSet) Add(e interface{}) bool { 12 | if !set.m[e] { 13 | set.m[e] = true 14 | return true 15 | } 16 | return false 17 | } 18 | 19 | func (set *HashSet) Remove(e interface{}) { 20 | delete(set.m, e) 21 | } 22 | 23 | func (set *HashSet) Clear(e interface{}) { 24 | set.m = make(map[interface{}]bool) 25 | } 26 | 27 | func (set *HashSet) Len() int { 28 | return len(set.m) 29 | } 30 | 31 | func (set *HashSet) Contains(e interface{}) bool { 32 | return set.m[e] 33 | } 34 | 35 | func (set *HashSet) Same(other *HashSet) bool { 36 | if other == nil { 37 | return false 38 | } 39 | if set.Len() != other.Len() { 40 | return false 41 | } 42 | for key := range set.m { 43 | if !other.Contains(key) { 44 | return false 45 | } 46 | } 47 | return true 48 | } 49 | 50 | func (set *HashSet) Elements() []interface{} { 51 | initialLen := len(set.m) 52 | snapshot := make([]interface{}, initialLen) 53 | actualLen := 0 54 | for key := range set.m { 55 | if actualLen < initialLen { 56 | snapshot[actualLen] = key 57 | } else { 58 | snapshot = append(snapshot, key) 59 | } 60 | actualLen++ 61 | } 62 | if actualLen < initialLen { 63 | snapshot = snapshot[:actualLen] 64 | } 65 | return snapshot 66 | } 67 | 68 | type Set interface { 69 | Add(e interface{}) bool 70 | Remove(e interface{}) bool 71 | Clear() 72 | Contains(e interface{}) bool 73 | Len() int 74 | Same(other Set) bool 75 | } 76 | 77 | func main() { 78 | set := &HashSet{make(map[interface{}]bool)} 79 | tmp := set.Add("a") 80 | fmt.Println(tmp) 81 | fmt.Println(set.m) 82 | } 83 | -------------------------------------------------------------------------------- /go-concurrency/mutex-example.go: -------------------------------------------------------------------------------- 1 | import ( 2 | "fmt" 3 | "sync" 4 | "sync/atomic" 5 | "time" 6 | "io" 7 | "os" 8 | ) 9 | type DataFile interface{ 10 | Read()(rsn int64, d Data, err error) 11 | Write(d Data)(wsn int64, err error) 12 | Rsn() int64 13 | Wsn() int64 14 | Datalen() uint32 15 | } 16 | 17 | type Data []byte 18 | 19 | type myDataFile struct{ 20 | f *os.File 21 | fmutex sync.RWMutex 22 | woffset int64 23 | roffset int64 24 | wmutex sync.Mutex 25 | rmutex sync.Mutex 26 | dataLen uint32 27 | } 28 | 29 | func NewDataFile(path string, dataLen uint32)(DataFile, error){ 30 | f,err:=os.Create(path) 31 | if err!=nil{ 32 | return nil, err 33 | } 34 | if dataLen == 0{ 35 | return nil, errors.New("Invalid data length!") 36 | } 37 | df := &myDataFile{f: f, dataLen: dataLen} 38 | return df,nil 39 | } 40 | 41 | func(df *myDataFile) Read()(rsn int64, d Data, err error){ 42 | var offset int64 43 | df.rmutex.Lock() 44 | offset = df.roffset 45 | df.roffset += int64(df.dataLen) 46 | df.rmutex.Unlock() 47 | 48 | rsn = offset / int64(df.dataLen) 49 | df.fmutex.RLock() 50 | defer df.fmutex.RUnlock() 51 | bytes := make([]byte, df.dataLen) 52 | _, err = df.f.ReadAt(bytes, offset) 53 | if err != nil{ 54 | return 55 | } 56 | d = bytes 57 | return 58 | } 59 | 60 | // better func Read() 61 | 62 | func(df *myDataFile) Read()(rsn int64, d Data, err error){ 63 | // 省略若干代码 64 | 65 | rsn = offset / int64(df.dataLen) 66 | bytes := make([]byte, df.dataLen) 67 | for { 68 | df.fmutex.RLock() 69 | _,err = df.f.ReadAt(bytes,offset) 70 | if err!=nil{ 71 | if err == io.EOF{ 72 | df.fmutex.RUlock() 73 | continue 74 | } 75 | df.fmutex.RUnLock() 76 | return 77 | } 78 | d = bytes 79 | df.fmutex.RUnlock() 80 | return 81 | } 82 | } 83 | 84 | func (df *myDataFile) Write(d Data)(wsn int64, err error){ 85 | //读取并更新偏移量 86 | var offset int64 87 | df.wmutex.Lock() 88 | offset = df.woffset 89 | df.woffset += int64(df.dataLen) 90 | df.wmutex.Unlock() 91 | 92 | //写入一个数据块 93 | wsn = offset / int64(df.dataLen) 94 | var bytes []byte 95 | if len(d) > int(df.dataLen){ 96 | bytes = d[0:df.dataLen] 97 | }else{ 98 | bytes = d 99 | } 100 | df.fmutex.Lock() 101 | df.fmutex.Unlock() 102 | _,err = df.f.Write(bytes) 103 | return 104 | } 105 | 106 | func (df *myDataFile) Rsn() int64{ 107 | df.rmutex.Lock() 108 | defer df.rmutex.Unlock() 109 | return df.roffset / int64(df.dataLen) 110 | } 111 | 112 | func (df *myDataFile) Wsn() int64{ 113 | df.rmutex.Lock() 114 | defer df.wmutex.Unlock() 115 | return df.woffset / int64(df.dataLen) 116 | } 117 | 118 | // 加入条件变量的Read 119 | func (df *myDataFile) Read()(rsn int64, d Data, err error){ 120 | //省略若干代码 121 | 122 | //读取一个数据块 123 | rsn = offset / int64(df.dataLen) 124 | bytes := make([]byte, df.dataLen) 125 | df.fmutex.RLock() 126 | defer df.fmutex.RUnlock() 127 | for { 128 | _,err = df.f.ReadAt(bytes, offset) 129 | if err!=nil{ 130 | if err == io.EOF{ 131 | df.rcond.Wait() 132 | continue 133 | } 134 | return 135 | } 136 | d = bytes 137 | return 138 | } 139 | } 140 | 141 | // 加入条件变量的Write 142 | func (df *myDataFile) Write(d Data)(wsn int64, err error){ 143 | 144 | //省略若干语句 145 | var bytes []byte 146 | df.fmutex.Lock() 147 | defer df.fmutex.Unlock() 148 | _,err = df.f.Write(bytes) 149 | df.rcond.Signal() 150 | return 151 | } 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /go-concurrency/select-channel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | unbufChan := make(chan int) 10 | sign := make(chan byte, 2) 11 | go func() { 12 | for i := 0; i < 10; i++ { 13 | select { 14 | case unbufChan <- i: 15 | case unbufChan <- i + 10: 16 | default: 17 | fmt.Println("default") 18 | } 19 | time.Sleep(time.Second) 20 | } 21 | close(unbufChan) 22 | fmt.Println("The channel is closed.") 23 | sign <- 0 24 | }() 25 | go func() { 26 | loop: 27 | for { 28 | select { 29 | case e, ok := <-unbufChan: 30 | if !ok { 31 | fmt.Println("Closed channel.") 32 | break loop 33 | } 34 | fmt.Printf("Reviece e: %d\n", e) 35 | time.Sleep(2 * time.Second) 36 | } 37 | } 38 | sign <- 1 39 | }() 40 | <-sign 41 | <-sign 42 | } 43 | -------------------------------------------------------------------------------- /go-concurrency/single-way-channel.go: -------------------------------------------------------------------------------- 1 | func (handler PersonHandlerImpl) Batch(origs <-chan Person) <- chan Person{ 2 | dests := make(chan Person, 100) 3 | go func(){ 4 | for{ 5 | p,ok := <-origs 6 | if !ok { 7 | close(dests) 8 | break 9 | } 10 | handler.Handle(p) 11 | dests <- p 12 | } 13 | }() 14 | return dests 15 | } -------------------------------------------------------------------------------- /go-concurrency/sync-once.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | var num int 11 | sign := make(chan bool) 12 | var once sync.Once 13 | f := func(ii int) func() { 14 | return func() { 15 | num = (num + ii*2) 16 | sign <- true 17 | } 18 | } 19 | for i := 0; i < 3; i++ { 20 | fi := f(i + 1) 21 | go once.Do(fi) 22 | for j := 0; j < 3; j++ { 23 | select { 24 | case <-sign: 25 | fmt.Println("Receive a signal") 26 | case <-time.After(100 * time.Millisecond): // 超时设置 27 | fmt.Println("Timeout!") 28 | } 29 | } 30 | fmt.Printf("Num: %d\n", num) 31 | } 32 | } 33 | 34 | // Receive a signal 35 | // Timeout! 36 | // Timeout! 37 | // Num: 2 38 | // Timeout! 39 | // Timeout! 40 | // Timeout! 41 | // Num: 2 42 | // Timeout! 43 | // Timeout! 44 | // Timeout! 45 | // Num: 2 46 | // fi just run one time 47 | 48 | // sync.Once类型的典型应用场景就是执行仅需要执行一次的任务。例如:数据块连接池初始化任务。又例如:一些需要持续运行的实时监测任务等等 49 | -------------------------------------------------------------------------------- /go-concurrency/sync-pool.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "runtime/debug" 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | func main() { 12 | // stop GC 13 | defer debug.SetGCPercent(debug.SetGCPercent(-1)) 14 | var count int32 15 | newFunc := func() interface{} { 16 | return atomic.AddInt32(&count, 1) 17 | } 18 | 19 | pool := sync.Pool{New: newFunc} 20 | v1 := pool.Get() 21 | fmt.Printf("v1: %v\n", v1) 22 | 23 | pool.Put(newFunc()) 24 | pool.Put(newFunc()) 25 | pool.Put(newFunc()) 26 | v2 := pool.Get() 27 | fmt.Printf("v2: %v\n", v2) 28 | debug.SetGCPercent(100) 29 | runtime.GC() 30 | v3 := pool.Get() 31 | fmt.Printf("v3: %v\n", v3) 32 | pool.New = nil 33 | v4 := pool.Get() 34 | fmt.Printf("v4: %v\n", v4) 35 | } 36 | -------------------------------------------------------------------------------- /go-concurrency/timeout-select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | go func() { 10 | var e int 11 | ok := true 12 | for { 13 | select { 14 | case e, ok = <-ch11: 15 | // 省略若干代码 16 | case ok = <-func() chan bool { 17 | timeout := make(chan bool, 1) 18 | go func() { 19 | time.Sleep(time.Millisecond) 20 | timeout <- false 21 | }() 22 | return timeout 23 | }(): 24 | fmt.Println("Timeout") 25 | break 26 | } 27 | if !ok { 28 | break 29 | } 30 | } 31 | }() 32 | } 33 | 34 | // 在运行时系统开始执行select语句的时候,会先对它所有的case中的元素表达式和通道表达式进行求值。 35 | // 这样才使得在运行时系统选择要执行case之前先制造出一个可用的超时触发器成为了可能。更具体地讲,在 36 | // 这些case被选择之前,第二个case后的接收语句会由下面这行代码代替: ok = <- timeout 37 | 38 | // 运行时系统在选择select语句的case的时候,只要case有多个,它就肯定不会为某一个case而等待。只有当 39 | // 所有的case后的发送语句或接收语句都无法被立即执行的时候,它才会阻塞住当前的GOroutine。当然,前提是 40 | // 没有default case。在等待期间,只要发现有某一个case后的语句可以立即被执行,那么运行时系统就会立即执行这个case 41 | // 在本例中,当无法立即从ch11通道中接收元素值的时候,运行时系统会随机判断是否可以立即接收timeout通道中的元素值。 42 | // 因此,一旦第一个case中的接收操作无法在1毫秒之内完成,我们给定超时子流程就会被执行 43 | -------------------------------------------------------------------------------- /go-concurrency/wait-group.go: -------------------------------------------------------------------------------- 1 | sign :=make(chan byte, 3) 2 | go func(){ // G2 3 | //... 4 | sign <- 2 5 | } 6 | 7 | go func(){ // G3 8 | //... 9 | sign <- 3 10 | } 11 | 12 | go func(){ // G4 13 | //... 14 | sign <- 4 15 | } 16 | 17 | for i:=0;i<3;i++{ 18 | fmt.Printf("G%d id ended.\n", <-sign) 19 | } 20 | 21 | var wg sync.WaitGroup 22 | wg.Add(3) 23 | 24 | go func(){ // G2 25 | //... 26 | wg.Done() 27 | } 28 | 29 | go func(){ // G3 30 | //... 31 | wg.Done() 32 | } 33 | 34 | go func(){ // G4 35 | //... 36 | wg.Done() 37 | } 38 | 39 | wg.Wait() 40 | fmt.Println("G2 G3 G4 are ended.") 41 | 42 | // 我们在启用G2 G3 G4之前声明了一个sync.WaitGroup类型的变量wg,并调用其值的Add方法以使其中的计数值等于将要额外启用的Goroutine的个数。 43 | // 后,在G2 G3 G4的运行即将结束之前,我们分别通过调用wg.Done方法将其中的计数值减去1.最后,我们在G1中调用wg.Wait方法以等待G2、G3、G4中的那3个 44 | // wg.Done方法的调用完成。待着3个调用完成之时,在wg.Wait()处的阻塞的G1会被唤醒,它后面的那条语句也会被立即执行 45 | // sync.WaitGroup 类型值的Add方法的第一次调用,应该发生在Done方法和Wait方法之前 -------------------------------------------------------------------------------- /go-http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | var mux map[string]func(http.ResponseWriter, *http.Request) 12 | 13 | func main() { 14 | // 没有使用http.HandleFunc 而是自己实现了一个Handler 15 | 16 | // http.HandleFunc("/", sayHello) 17 | // http.HandleFunc("/bye", sayBye) 18 | fmt.Println("The simple server starts") 19 | server := http.Server{ 20 | Addr: ":8080", 21 | Handler: &myHandler{}, 22 | ReadTimeout: time.Second * 5, 23 | } 24 | 25 | mux = make(map[string]func(http.ResponseWriter, *http.Request)) 26 | 27 | mux["/"] = sayHello 28 | mux["/bye"] = sayBye 29 | 30 | err := server.ListenAndServe() 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | 35 | } 36 | 37 | type myHandler struct{} //定义这个结构的作用是为了能实现ServeHTTP 方法 38 | 39 | func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 40 | fmt.Println("I am ServeHTTP") 41 | if h, ok := mux[r.URL.String()]; ok { 42 | h(w, r) 43 | return 44 | } 45 | } 46 | 47 | func sayHello(w http.ResponseWriter, r *http.Request) { 48 | io.WriteString(w, "Hello world, this is a simple server") 49 | } 50 | 51 | func sayBye(w http.ResponseWriter, r *http.Request) { 52 | io.WriteString(w, "Bye bye, this is a simple server") 53 | } 54 | -------------------------------------------------------------------------------- /go-libary/image.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | "image/png" 7 | "log" 8 | "math/rand" 9 | "os" 10 | "time" 11 | ) 12 | 13 | func main() { 14 | width, height := 2048, 1024 15 | canvas := NewCanvas(image.Rect(0, 0, width, height)) 16 | canvas.DrawGradient() 17 | 18 | // Draw a set of spirals randomly over the image 19 | rand.Seed(time.Now().UTC().UnixNano()) 20 | for i := 0; i < 100; i++ { 21 | x := float64(width) * rand.Float64() 22 | y := float64(height) * rand.Float64() 23 | color := color.RGBA{uint8(rand.Intn(255)), 24 | uint8(rand.Intn(255)), 25 | uint8(rand.Intn(255)), 26 | 255} 27 | 28 | canvas.DrawSpiral(color, Vector{x, y}) 29 | } 30 | 31 | outFilename := "spirals.png" 32 | outFile, err := os.Create(outFilename) 33 | if err != nil { 34 | log.Fatal(err) 35 | } 36 | defer outFile.Close() 37 | log.Print("Saving image to: ", outFilename) 38 | png.Encode(outFile, canvas) 39 | } 40 | -------------------------------------------------------------------------------- /go-libary/net-http/HiJack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func HiJack(w http.ResponseWriter, r *http.Request) { 9 | hj, ok := w.(http.Hijacker) 10 | if !ok { 11 | http.Error(w, "webservr doesn't support hijacking", http.StatusInternalServerError) 12 | return 13 | } 14 | conn, bufrw, err := hj.Hijack() 15 | if err != nil { 16 | http.Error(w, err.Error(), http.StatusInternalServerError) 17 | return 18 | } 19 | defer conn.Close() 20 | bufrw.WriteString("Now we're speaking raw TCP. Say hi: \n") 21 | bufrw.Flush() 22 | 23 | fmt.Fprintf(bufrw, "You said: %s Bye.\n", "Good") 24 | bufrw.Flush() 25 | } 26 | 27 | func main() { 28 | http.HandleFunc("/hijack", HiJack) 29 | err := http.ListenAndServe(":9999", nil) 30 | if err != nil { 31 | fmt.Println(err) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /go-libary/net-http/net-http-body.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | client := &http.Client{} 12 | request, err := http.NewRequest("GET", "http://www.hao123.com", nil) 13 | if err != nil { 14 | fmt.Println(err) 15 | } 16 | cookie := &http.Cookie{Name: "userId", Value: strconv.Itoa(12345)} 17 | request.AddCookie(cookie) 18 | request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") 19 | request.Header.Set("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3") 20 | request.Header.Set("Accept-Encoding", "gzip,deflate,sdch") 21 | request.Header.Set("Accept-Language", "zh-CN,zh;q=0.8") 22 | request.Header.Set("Cache-Control", "max-age=0") 23 | request.Header.Set("Connection", "keep-alive") 24 | response, err := client.Do(request) 25 | if err != nil { 26 | fmt.Println(err) 27 | return 28 | } 29 | defer response.Body.Close() 30 | fmt.Println(response.StatusCode) 31 | if response.StatusCode == 200 { 32 | r, err := ioutil.ReadAll(response.Body) 33 | if err != nil { 34 | fmt.Println(err) 35 | } 36 | fmt.Println(string(r)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /go-libary/net-http/net-http-handle.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | // "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.Handle("/test", http.FileServer(http.Dir("./"))) 10 | http.Handle("/download/", http.StripPrefix("/download/", http.FileServer(http.Dir("./")))) 11 | http.Handle("/code/", http.StripPrefix("/code/", http.FileServer(http.Dir("/Users/path/code")))) // 会自动去找目录下的index.html文件并且渲染,如果没有的话,就显示目录文件 12 | http.ListenAndServe(":9998", nil) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /go-libary/net-http/net-http.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | // resp, err := http.Get("http://www.hao123.com") 11 | // defer resp.Body.Close() 12 | // body, err := ioutil.ReadAll(resp.Body) 13 | // if err != nil { 14 | // fmt.Println("Error!") 15 | // } 16 | // fmt.Println(body) 17 | 18 | // resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) 19 | // resp, err := http.PostForm("http://example.com/form", url.Values{"key": {"Value"}, "id": {"123"}}) 20 | client := &http.Client{ 21 | CheckRedirect: redirectPolicyFunc, 22 | } 23 | resp, _ := client.Get("http://www.hao123.com") 24 | 25 | req, err := client.NewRequest("GET", "http://example.com", nil) 26 | req.Header.Add("If-None-Match", `W/"wyzzy"`) 27 | resp, err := client.Do(req) 28 | tr := &http.Transport{ 29 | TLSClientConfig: &tls.Config{RootCAs: pool}, 30 | DisableCompression: true, 31 | } 32 | client := &http.Client{Transport: tr} 33 | resp, err := client.Get("http://example.com") 34 | 35 | http.Handle("/foo", fooHandler) 36 | http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { 37 | fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) 38 | }) 39 | log.Fatal(http.ListenAndServe(":8080", nil)) 40 | 41 | s := &http.Server{ 42 | Addr: ":8080", 43 | Handler: myHandler, 44 | ReadTimeout: 10 * time.Second, 45 | WriteTimeout: 10 * time.Second, 46 | MaxHeaderBytes: 1 << 20, 47 | } 48 | log.Fatal(s.ListenAndServe()) 49 | 50 | 51 | func HelloServer(w http.ResponseWriter, req *http.Request) { 52 | io.WriteString(w, "hello, world!\n") 53 | } 54 | 55 | func main() { 56 | http.HandleFunc("/hello", HelloServer) 57 | log.Fatal(http.ListenAndServe(":8080", nil)) 58 | } 59 | 60 | func handler(w http.ResponseWriter, r *http.Request) 61 | { 62 | w.Header().Set("Content-Type", "text/plain") 63 | w.Write([]byte("This is an example server.\n")) 64 | } 65 | 66 | func main() { 67 | http.HandleFunc("/", handler) 68 | log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") 69 | err := http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil) 70 | log.Fatal(err) 71 | } 72 | 73 | type Cookie struct { 74 | Name string 75 | Value string 76 | Path string 77 | Domain string 78 | Expires time.Time 79 | RawExpires string 80 | MaxAge int 81 | Secure bool 82 | HttpOnly bool 83 | Raw string 84 | Unparsed []string 85 | } 86 | 87 | log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/usr/share/doc")))) 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /go-libary/net-http/net-server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func Test(w http.ResponseWriter, r *http.Request) { 9 | fmt.Fprintln(w, "just for test!") 10 | } 11 | func main() { 12 | newserver := http.Server{ 13 | Addr: ":9999", 14 | ReadTimeout: 0, 15 | WriteTimeout: 0, 16 | } 17 | mux := http.NewServeMux() 18 | mux.Handle("/", http.FileServer(http.Dir("./"))) 19 | mux.HandleFunc("/test", Test) 20 | newserver.Handler = mux 21 | err := newserver.ListenAndServe() 22 | if err != nil { 23 | fmt.Println(err) 24 | } 25 | fmt.Println(err) 26 | // err := http.ListenAndServe(":9999", mux) 27 | // if err != nil { 28 | // fmt.Println(err) 29 | // } 30 | } 31 | -------------------------------------------------------------------------------- /go-libary/net-http/newServeMux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func Test(w http.ResponseWriter, r *http.Request) { 9 | fmt.Fprintln(w, "just for test!") 10 | } 11 | 12 | func main() { 13 | mux := http.NewServeMux() 14 | mux.Handle("/", http.FileServer(http.Dir("/home"))) 15 | mux.HandleFunc("/test", Test) 16 | err := http.ListenAndServe(":9999", mux) 17 | if err != nil { 18 | fmt.Println(err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /go-libary/net-http/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | // "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | func Test() { 10 | req, err := http.NewRequest("GET", "http://www.hao123.com", nil) 11 | if err != nil { 12 | fmt.Println(err) 13 | return 14 | } 15 | req.SetBasicAuth("test", "123456") 16 | fmt.Println(req.Proto) 17 | cookie := &http.Cookie{ 18 | Name: "test", 19 | Value: "12", 20 | } 21 | req.AddCookie(cookie) 22 | fmt.Println(req.Cookie("test")) //获取cookie 23 | fmt.Println(req.Cookies()) 24 | req.Header.Set("User-Agent", "user-agent") 25 | fmt.Println(req.UserAgent()) 26 | fmt.Println(req.URL) 27 | client := &http.Client{} 28 | resp, err := client.Do(req) 29 | if err != nil { 30 | fmt.Println(err) 31 | return 32 | } 33 | defer resp.Body.Close() 34 | if resp.StatusCode == 200 { 35 | content, _ := ioutil.ReadAll(resp.Body) 36 | fmt.Println(string(content)) 37 | } 38 | } 39 | 40 | func main() { 41 | Test() 42 | } 43 | -------------------------------------------------------------------------------- /go-libary/parse-ip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | if len(os.Args) != 2 { 11 | fmt.Fprintf(os.Stderr, "Usage: %s ip-addr\n", os.Args[0]) 12 | os.Exit(1) 13 | } 14 | fmt.Println(os.Args[0]) 15 | name := os.Args[1] 16 | addr := net.ParseIP(name) 17 | if addr == nil { 18 | fmt.Println("Invalid address") 19 | } else { 20 | fmt.Println("The address is ", addr.String()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go-libary/try-spider.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "golang.org/x/net/html" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func visit(links []string, n *html.Node) []string { 11 | if n.Type == html.ElementNode && n.Data == 'a' { 12 | for _, a := range n.Attr { 13 | if a.Key == "href" { 14 | links = append(links, a.Val) 15 | } 16 | } 17 | } 18 | for c := n.FirstChild; c != nil; c = c.NextSibling { 19 | links = visit(links, c) 20 | } 21 | return links 22 | } 23 | 24 | func main() { 25 | for _, url := range os.Args[1:] { 26 | links, err := findLinks(url) 27 | if err != nil { 28 | fmt.Fprintf(os.Stderr, "findlinks2: %v\n", err) 29 | continue 30 | } 31 | for _, link := range links { 32 | fmt.Println(link) 33 | } 34 | } 35 | } 36 | 37 | func findLinks(url string) ([]string, error) { 38 | resp, err := http.Get(url) 39 | if err != nil { 40 | return nil, err 41 | } 42 | if resp.StatusCode != http.StatusOK { 43 | resp.Body.Close() 44 | return nil, fmt.Errorf("getting %s: %s", url, resp.Status) 45 | } 46 | doc, err := html.Parse(resp.Body) 47 | resp.Body.Close() 48 | if err != nil { 49 | return nil, fmt.Errorf("pax resing %s as HTML: %v", url, err) 50 | } 51 | return visit(nil, doc), nil 52 | } 53 | -------------------------------------------------------------------------------- /go-slice-usage.go: -------------------------------------------------------------------------------- 1 | b := [2]string{"Penn", "Teller"} 2 | 3 | b:= [...]string{"Penn", "Teller"} 4 | 5 | letters := []string{"a","b","c","d"} 6 | 7 | func make([]T, len, cap) []T 8 | 9 | var s []byte 10 | s = make([]byte, 5, 5) 11 | 12 | b := []byte{'g', 'o', 'l', 'a', 'n', 'g'} 13 | // b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b 14 | 15 | // b[:2] == []byte{'g', 'o'} 16 | // b[2:] == []byte{'l', 'a', 'n', 'g'} 17 | // b[:] == b 18 | 19 | x := [3]string{"Лайка", "Белка", "Стрелка"} 20 | s := x[:] // a slice referencing the storage of x 21 | 22 | d := []byte{'r', 'o', 'a', 'd'} 23 | e := d[2:] 24 | // e == []byte{'a', 'd'} 25 | e[1] = 'm' 26 | // e == []byte{'a', 'm'} 27 | // d == []byte{'r', 'o', 'a', 'm'} 28 | 29 | t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0 30 | for i := range s { 31 | t[i] = s[i] 32 | } 33 | s = t 34 | 35 | func AppendByte(slice []byte, data ...byte) []byte { 36 | m := len(slice) 37 | n := m + len(data) 38 | if n > cap(slice) { // if necessary, reallocate 39 | // allocate double what's needed, for future growth. 40 | newSlice := make([]byte, (n+1)*2) 41 | copy(newSlice, slice) 42 | slice = newSlice 43 | } 44 | slice = slice[0:n] 45 | copy(slice[m:n], data) 46 | return slice 47 | } 48 | 49 | p := []byte{2, 3, 5} 50 | p = AppendByte(p, 7, 11, 13) 51 | // p == []byte{2, 3, 5, 7, 11, 13} 52 | 53 | 54 | func CopyDigits(filename string) []byte { 55 | b, _ := ioutil.ReadFile(filename) 56 | b = digitRegexp.Find(b) 57 | c := make([]byte, len(b)) 58 | copy(c, b) 59 | return c 60 | } 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /go-timeout-moving-on.go: -------------------------------------------------------------------------------- 1 | timeout := make(chan bool, 1) 2 | go func() { 3 | time.Sleep(1 * time.Second) 4 | timeout <- true 5 | } 6 | 7 | select { 8 | case <-ch: 9 | // a read from ch has occurred 10 | case <-timeout: 11 | // read from ch has timed out 12 | } 13 | 14 | func Query(conns []Conn, query string) Result { 15 | ch := make(chan Result, 1) 16 | for _, conn := range conns { 17 | go func(c Conn) { 18 | select { 19 | case ch <- c.DoQuery(query): 20 | default: 21 | } 22 | }(conn) 23 | } 24 | return <-ch 25 | } -------------------------------------------------------------------------------- /gob.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "fmt" 7 | "log" 8 | ) 9 | 10 | type P struct { 11 | X, Y, Z int 12 | Name string 13 | } 14 | 15 | type Q struct { 16 | X, Y int32 17 | Name string 18 | } 19 | 20 | func main() { 21 | var network bytes.Buffer 22 | enc := gob.NewEncoder(&network) 23 | dec := gob.NewDecoder(&network) 24 | err := enc.Encode(P{3, 4, 5, "Pythagoras"}) // 加码器 25 | if err != nil { 26 | log.Fatal("encode error: ", err) 27 | } 28 | 29 | var q Q 30 | err = dec.Decode(&q) // 从加码器中读取值 进行解码 31 | if err != nil { 32 | log.Fatal("decode error: ", err) 33 | } 34 | fmt.Printf("%q: {%d,%d}\n", q.Name, q.X, q.Y) 35 | } 36 | -------------------------------------------------------------------------------- /goroutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func f(from string) { 6 | for i := 0; i < 3; i++ { 7 | fmt.Println(from, ":", i) 8 | } 9 | } 10 | 11 | func main() { 12 | f("direct") 13 | go f("goroutine") 14 | go func(msg string) { 15 | fmt.Println(msg) 16 | }("going") 17 | 18 | var input string 19 | fmt.Scanln(&input) 20 | fmt.Println("done") 21 | } 22 | -------------------------------------------------------------------------------- /handler-as-middleware.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func OurLoggingHandler(h http.Handler) http.Handler { 9 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Println(*r.URL) 11 | h.ServeHTTP(w, r) // http.Handler 需要实现 ServeHTTP(ResponseWriter, *Request) 这个方法 12 | }) 13 | } 14 | 15 | func main() { 16 | fileHandler := http.FileServer(http.Dir("/Users/path/code")) 17 | wrappedHandler := OurLoggingHandler(fileHandler) 18 | http.ListenAndServe(":9000", wrappedHandler) 19 | } 20 | -------------------------------------------------------------------------------- /http-basic-auth.go: -------------------------------------------------------------------------------- 1 | 2 | type ViewFunc func(http.ResponseWriter, *http.Request) 3 | 4 | func BasicAuth(f ViewFunc) ViewFunc { 5 | return func(w http.ResponseWriter, r *http.Request) { 6 | db, err := database.DB() 7 | CheckErr(err, w) 8 | defer db.Close() 9 | timestamp := r.URL.Query().Get("timestamp") 10 | t := time.Now() 11 | fmt.Println(t) 12 | tm, _ := time.Parse("20060102150405", timestamp) 13 | fmt.Println(tm) 14 | x := t.Sub(tm).Minutes() 15 | fmt.Println(x) 16 | basicAuthPrefix := "Basic " 17 | auth := r.Header.Get("Authorization") //获取 request header 18 | if strings.HasPrefix(auth, basicAuthPrefix) { 19 | payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):]) // 解码认证信息 20 | if err == nil { 21 | account := model.Account{} 22 | pair := bytes.SplitN(payload, []byte(":"), 2) 23 | appid := string(pair[0]) 24 | db.Joins("JOIN apps ON apps.account_id = accounts.id").Where("apps.sid = ?", appid).Find(&account) 25 | sign_str := appid + account.AuthToken + timestamp 26 | sha1Encoder := sha1.New() 27 | sha1Encoder.Write([]byte(sign_str)) 28 | signResult := sha1Encoder.Sum(nil) 29 | sign := fmt.Sprintf("%x", signResult) 30 | fmt.Println(sign) 31 | if len(pair) == 2 && bytes.Equal(pair[0], []byte(appid)) && bytes.Equal(pair[1], []byte(sign)) { 32 | f(w, r) 33 | return 34 | } 35 | } 36 | } 37 | // 认证失败,提示 401 Unauthorized 38 | // Restricted 可以改成其他的值 39 | w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) 40 | w.WriteHeader(http.StatusUnauthorized) 41 | } 42 | } 43 | 44 | func CheckErr(err error, res http.ResponseWriter) { 45 | if err != nil { 46 | http.Error(res, err.Error(), http.StatusInternalServerError) 47 | log.Println(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /http-middleware-two.go: -------------------------------------------------------------------------------- 1 | package httpmiddleware 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type AppendMiddleware struct { 8 | handler http.Handler 9 | } 10 | 11 | // ServeHTTP 是http.Handler接口默认使用的方法 12 | func (this *AppendMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { 13 | // this.handler.ServeHTTP(w, r) // 这是底层的 ServeHTTP, w r传入到了myHandler中 14 | w.Write([]byte("Hey, this is middleware!")) 15 | } 16 | 17 | func myHandler(w http.ResponseWriter, r *http.Request) { 18 | w.Write([]byte("Hello world!")) 19 | } 20 | 21 | func main() { 22 | mid := &AppendMiddleware{http.HandlerFunc(myHandler)} // myHandler is a 闭包。传入了 w和r以及它的执行代码 23 | http.ListenAndServe(":8080", mid) 24 | } 25 | -------------------------------------------------------------------------------- /http-middleware.go: -------------------------------------------------------------------------------- 1 | package httpmiddleware 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type SingleHost struct { 8 | handler http.Handler // the http.Handler interface 9 | allowedHost string 10 | } 11 | 12 | // ServeHTTP is the middleware 13 | func (this *SingleHost) ServeHTTP(w http.ResponseWriter, r *http.Request) { 14 | println(r.Host) 15 | if r.Host == this.allowedHost { 16 | this.handler.ServeHTTP(w, r) 17 | } else { 18 | w.WriteHeader(403) 19 | } 20 | } 21 | 22 | func myHandler(w http.ResponseWriter, r *http.Request) { 23 | w.Write([]byte("hello world!")) 24 | } 25 | 26 | func main() { 27 | single := &SingleHost{ 28 | handler: http.HandlerFunc(myHandler), // HandlerFunc is a type and the type is a function 29 | allowedHost: "localhost:8080", 30 | } 31 | http.ListenAndServe(":8080", single) 32 | } 33 | -------------------------------------------------------------------------------- /if_else.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | if 7%2 == 0 { 7 | fmt.Println("7 is even") 8 | } else { 9 | fmt.Println("7 is odd") 10 | } 11 | 12 | if num := 9; num < 0 { 13 | fmt.Println(num, "is negative") 14 | } else if num < 10 { 15 | fmt.Println(num, "has 1 digit") 16 | } else { 17 | fmt.Println(num, "has multiple digits") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | type geometry interface { // 任何类型 包括struct 都可以调用interface中的方法。可以看出interface是类型的父类 9 | area() float64 // rect 和 circle的方法名相同,但是根据类型不同调用不同代码 10 | perim() float64 11 | } 12 | 13 | type rect struct { 14 | width, height float64 15 | } 16 | 17 | type circle struct { 18 | radius float64 19 | } 20 | 21 | func (r *rect) area() float64 { 22 | return r.width * r.height 23 | } 24 | 25 | func (r rect) perim() float64 { 26 | return 2*r.width + 2*r.height 27 | } 28 | 29 | func (c circle) area() float64 { 30 | return math.Pi * c.radius * c.radius 31 | } 32 | func (c circle) perim() float64 { 33 | return 2 * math.Pi * c.radius 34 | } 35 | 36 | func measure(g geometry) { 37 | fmt.Println("here: ", g) 38 | fmt.Println(g.area()) // rect 和 circle的方法名相同,但是根据类型不同调用不同代码 39 | fmt.Println(g.perim()) 40 | } 41 | 42 | func main() { 43 | r := rect{width: 10, height: 10} 44 | c := circle{radius: 5} 45 | 46 | measure(&r) 47 | measure(c) 48 | } 49 | 50 | // 接口: 接口中集成很多方法,或嵌套接口。在使用的时候,根据传的类型的不同,调用其该类型定义的方法 51 | // go中没有继承, 所以用接口可以模拟实现类的继承。 可以看成interface就是父类, 子类调用其中的方法时,就是调用该对应子类的方法 52 | -------------------------------------------------------------------------------- /json-and-go.go: -------------------------------------------------------------------------------- 1 | import ( 2 | "encoding/json" 3 | ) 4 | 5 | func Marshal(v interface{}) ([]byte, error) 6 | 7 | type Message struct { 8 | Name string 9 | Body string 10 | Time int64 11 | } 12 | 13 | m := Message{"Alice", "Hello", 1294706395881547000} 14 | 15 | b, err := json.Marshal(m) 16 | b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`) 17 | 18 | func Unmarshal(data []byte, v interface{}) error 19 | 20 | var m Message 21 | 22 | err := json.Unmarshal(b, &m) 23 | 24 | m = Message{ 25 | Name: "Alice", 26 | Body: "Hello", 27 | Time: 1294706395881547000, 28 | } 29 | 30 | var i interface{} 31 | 32 | i = "a string" 33 | i = 2026 34 | i = 2.333 35 | 36 | r := i.(float64) 37 | fmt.Println("the circle's area", math.Pi*r*r) 38 | 39 | switch v := i.(type) { 40 | case int: 41 | fmt.Println("twice i is", v*2) 42 | case float64: 43 | fmt.Println("the reciprocal of i is", 1/v) 44 | case string: 45 | h := len(v) / 2 46 | fmt.Println("i swapped by halves is", v[h:]+v[:h]) 47 | default: 48 | // i isn't one of the types above 49 | } 50 | 51 | b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`) // json is a string 52 | 53 | var f interface{} 54 | 55 | err := json.Unmarshal(b, &f) 56 | 57 | f = map[string]interface{}{ 58 | "Name": "Wednesday", 59 | "Age": 6, 60 | "Parents": []interface{}{ 61 | "Gomez", 62 | "Morticia", 63 | }, 64 | } 65 | 66 | m := f.(map[string]interface{}) 67 | 68 | for k, v := range m { 69 | switch vv := v.(type) { 70 | case string: 71 | fmt.Println(k, "is string", vv) 72 | case int: 73 | fmt.Println(k, "is int", vv) 74 | case []interface{}: 75 | fmt.Println(k, "is an array:") 76 | for i, u := range vv { 77 | fmt.Println(i, u) 78 | } 79 | default: 80 | fmt.Println(k, "is of a type I don't know how to handle") 81 | } 82 | } 83 | 84 | type FamilyMember struct { 85 | Name string 86 | Age int 87 | Parents []string 88 | } 89 | 90 | var m FamilyMember 91 | err := json.Unmarshal(b, &m) 92 | 93 | type IncomingMessage struct { 94 | Cmd *Command 95 | Msg *Message 96 | } 97 | 98 | func NewDecoder(r io.Reader) *Decorder 99 | func NewEncoder(r io.Writer) *Encoder 100 | 101 | package main 102 | 103 | import ( 104 | "encoding/json" 105 | "log" 106 | "os" 107 | ) 108 | 109 | func main(){ 110 | dec := json.NewDecoder(os.Stdin) 111 | enc := json.NewEncoder(os.Stdout) 112 | for { 113 | var v map[string]interface{} 114 | if err := dec.Decorder(&v); err != nil { 115 | log.Println(err) 116 | return 117 | } 118 | for k := range v { 119 | if k!= "Name" { 120 | delete(v, k) 121 | } 122 | } 123 | if err := enc.Encode(&v); err != nil { 124 | log.Println(err) 125 | } 126 | } 127 | } 128 | 129 | // Due to the ubiquity of Readers and Writers, these Encoder and Decoder types can be used in a broad 130 | // range of scenarios, such as reading and writing to HTTP connections, WebSockets, or files. 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /json-array.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import( 4 | "fmt" 5 | "encoding/json" 6 | ) 7 | 8 | func main() { 9 | type T struct { 10 | Endpoint string `json:"endpoint"` 11 | Counter string `json:"counter"` 12 | Dstype string `json:"dstype"` 13 | Step int `json:"step"` 14 | Value []struct { 15 | Timestamp int `json:"timestamp"` 16 | Value float64 `json:"value"` 17 | } `json:"Values"` 18 | } 19 | t := new(T) 20 | err := json.Unmarshal([]byte(s), t) 21 | if err != nil { 22 | fmt.Println(err) 23 | } 24 | fmt.Printf("%+v", *t) 25 | } 26 | -------------------------------------------------------------------------------- /json-list.go: -------------------------------------------------------------------------------- 1 | // Using go to unmarshal json lists with multiple types 2 | 3 | // http://mattyjwilliams.blogspot.co.uk/2013/01/using-go-to-unmarshal-json-lists-with.html 4 | package main 5 | 6 | import ( 7 | "encoding/json" 8 | "fmt" 9 | ) 10 | 11 | var jsonStr = []byte(` 12 | { 13 | "things": [ 14 | { 15 | "name": "Alice", 16 | "age": 37 17 | }, 18 | { 19 | "city": "Ipoh", 20 | "country": "Malaysia" 21 | }, 22 | { 23 | "name": "Bob", 24 | "age": 36 25 | }, 26 | { 27 | "city": "Northampton", 28 | "country": "England" 29 | } 30 | ] 31 | }`) 32 | 33 | func main() { 34 | personsA, placesA := solutionA(jsonStr) 35 | fmt.Printf("%d %d\n", len(personsA), len(placesA)) 36 | 37 | personsB, placesB := solutionB(jsonStr) 38 | fmt.Printf("%d %d\n", len(personsB), len(placesB)) 39 | 40 | personsC, placesC := solutionC(jsonStr) 41 | fmt.Printf("%d %d\n", len(personsC), len(placesC)) 42 | } 43 | 44 | // Common to both solutions 45 | type Person struct { 46 | Name string 47 | Age int 48 | } 49 | 50 | type Place struct { 51 | City string 52 | Country string 53 | } 54 | 55 | //Solution A 56 | //Unmarshal into a map 57 | //Type assert when we need it 58 | func solutionA(jsonStr []byte) ([]Person, []Place) { 59 | persons := []Person{} 60 | places := []Place{} 61 | var data map[string][]map[string]interface{} // {'key' => [{'key'=> },{'key'=> }]} 这样的结构 62 | err := json.Unmarshal(jsonStr, &data) 63 | if err != nil { 64 | fmt.Println(err) 65 | return persons, places 66 | } 67 | 68 | for i := range data["things"] { 69 | item := data["thing"][i] 70 | if item["name"] != nil { 71 | persons = addPerson(persons, item) 72 | } else { 73 | places = addPlace(places, item) 74 | } 75 | } 76 | return persons, places 77 | } 78 | 79 | func addPerson(persons []Person, item map[string]interface{}) []Person { 80 | name, _ := item["name"].(string) 81 | age, _ := item["age"].(int) 82 | person := Person{name, age} 83 | persons = append(persons, person) 84 | return persons 85 | } 86 | 87 | func addPlace(places []Place, item map[string]interface{}) []Place { 88 | city, _ := item["city"].(string) 89 | country, _ := item["city"].(string) 90 | place := Place{city, country} 91 | places = append(places, place) 92 | return places 93 | } 94 | 95 | // SolutionB 96 | 97 | type Mixed struct { 98 | Name string `json:"name"` 99 | Age int `json:"age"` 100 | City string `json:"city"` 101 | Country string `json:"country"` 102 | } 103 | 104 | func solutionB(jsonStr []byte) ([]Person, []Place) { 105 | persons := []Person{} 106 | places := []Place{} 107 | var data map[string][]Mixed 108 | err := json.Unmarshal(jsonStr, &data) 109 | if err != nil { 110 | fmt.Println(err) 111 | return persons, places 112 | } 113 | 114 | for i := range data["thing"] { 115 | item := data["things"][i] 116 | if item.Name != "" { 117 | persons = append(persons, Person{item.Name, item.Age}) 118 | } else { 119 | places = append(places, Place{item.City, item.Country}) 120 | } 121 | } 122 | return persons, places 123 | } 124 | 125 | //SolutionC 126 | 127 | func solutionC(jsonStr []byte) ([]Person, []Place) { 128 | people := []Person{} 129 | places := []Place{} 130 | var data map[string][]json.RawMessage 131 | err := json.Unmarshal(jsonStr, &data) 132 | if err != nil { 133 | fmt.Println(err) 134 | return people, places 135 | } 136 | for _, thing := range data["thing"] { 137 | people = addPersonC(thing, people) 138 | places = addPlaceC(thing, places) 139 | } 140 | return people, places 141 | } 142 | 143 | func addPersonC(thing json.RawMessage, people []Person) []Person { 144 | person := Person{} 145 | if err := json.Unmarshal(thing, &person); err != nil { 146 | fmt.Println(err) 147 | } else { 148 | if person != *new(Person) { 149 | people = append(people, person) 150 | } 151 | } 152 | return people 153 | } 154 | 155 | func addPlaceC(thing json.RawMessage, places []Place) []Place { 156 | place := Place{} 157 | if err := json.Unmarshal(thing, &place); err != nil { 158 | fmt.Println(err) 159 | } else { 160 | if place != *new(Place) { 161 | places = append(places, place) 162 | } 163 | } 164 | return places 165 | } 166 | -------------------------------------------------------------------------------- /json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | type Response1 struct { 10 | Page int 11 | Fruits []string 12 | } 13 | 14 | type Response2 struct { 15 | Page int `json:"Page"` 16 | Fruits []string `json:fruits` 17 | } 18 | 19 | func main() { 20 | bolB, _ := json.Marshal(true) 21 | fmt.Println(string(bolB)) 22 | 23 | intB, _ := json.Marshal(1) 24 | fmt.Println(string(intB)) 25 | 26 | fltB, _ := json.Marshal(2.34) 27 | fmt.Println(string(fltB)) 28 | 29 | strB, _ := json.Marshal("gopher") 30 | fmt.Println(string(strB)) 31 | 32 | slcD := []string{"apple", "peach", "pear"} 33 | slcB, _ := json.Marshal(slcD) 34 | 35 | fmt.Println(string(slcB)) 36 | 37 | mapD := map[string]int{"apple": 5, "lettuce": 7} 38 | mapB, _ := json.Marshal(mapD) 39 | fmt.Println(string(mapB)) 40 | 41 | res1D := &Response1{ 42 | Page: 1, 43 | Fruits: []string{"apple", "peach", "pear"}} 44 | res1B, _ := json.Marshal(res1D) 45 | fmt.Println(string(res1B)) 46 | res2D := &Response2{ 47 | Page: 1, 48 | Fruits: []string{"apple", "peach", "pear"}} 49 | res2B, _ := json.Marshal(res2D) 50 | fmt.Println(string(res2B)) 51 | 52 | byt := []byte(`{"num":6.13,"strs":["a","b"]}`) 53 | var dat map[string]interface{} 54 | 55 | if err := json.Unmarshal(byt, &dat); err != nil { 56 | panic(err) 57 | } 58 | fmt.Println(dat) 59 | 60 | num := dat["num"].(float64) 61 | fmt.Println(num) 62 | 63 | strs := dat["strs"].([]interface{}) 64 | str1 := strs[0].(string) 65 | fmt.Println(str1) 66 | // We can also decode JSON into custom data types. This has the advantages of adding additional type-safety to our programs and eliminating the need for type assertions when accessing the decoded data. 67 | str := `{"page": 1, "fruits": ["apple", "peach"]}` 68 | res := Response2{} 69 | json.Unmarshal([]byte(str), &res) 70 | fmt.Println(res) 71 | fmt.Println(res.Fruits[0]) 72 | // In the examples above we always used bytes and strings as intermediates between the data and JSON representation on standard out. We can also stream JSON encodings directly to os.Writers like os.Stdout or even HTTP response bodies. 73 | enc := json.NewEncoder(os.Stdout) 74 | d := map[string]int{"apple": 5, "lettuce": 7} 75 | enc.Encode(d) 76 | } 77 | 78 | // true 79 | // 1 80 | // 2.34 81 | // "gopher" 82 | // ["apple","peach","pear"] 83 | // {"apple":5,"lettuce":7} 84 | // {"Page":1,"Fruits":["apple","peach","pear"]} 85 | // {"Page":1,"Fruits":["apple","peach","pear"]} 86 | // map[num:6.13 strs:[a b]] 87 | // 6.13 88 | // a 89 | // {1 [apple peach]} 90 | // apple 91 | // {"apple":5,"lettuce":7} 92 | -------------------------------------------------------------------------------- /learning_golang/src/algorithm/fibonacci/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func fib(n int) int { 6 | x, y := 0, 1 7 | for i := 0; i < n; i++{ 8 | x, y = y, x+y 9 | } 10 | return y 11 | } 12 | 13 | func main(){ 14 | fmt.Println(fib(10)) 15 | } 16 | -------------------------------------------------------------------------------- /learning_golang/src/algorithm/gcd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func gcd(x, y int) int { 6 | for y != 0 { 7 | x, y = y, x%y 8 | } 9 | return x 10 | } 11 | 12 | func main() { 13 | fmt.Println(gcd(4, 6)) 14 | } 15 | -------------------------------------------------------------------------------- /learning_golang/src/alice/power.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/justinas/alice" 8 | "github.com/justinas/nosurf" 9 | "gopkg.in/throttled/throttled.v1" 10 | ) 11 | 12 | func timeoutHandler(h http.Handler) http.Handler { 13 | return http.TimeoutHandler(h, 1*time.Second, "timed out") 14 | } 15 | 16 | func myApp(w http.ResponseWriter, r *http.Request) { 17 | w.Write([]byte("Hello World!")) 18 | } 19 | 20 | func main() { 21 | th := throttled.Interval(throttled.PerSec(10), 1, &throttled.VaryBy{Path: true}, 50) 22 | myHandler := http.HandlerFucn(myApp) 23 | 24 | chain := alice.New(th.Throttle, timeoutHandler, nosurf.NewPure).Then(myHandler) 25 | http.ListenAndServe(":8000", chain) 26 | } 27 | -------------------------------------------------------------------------------- /learning_golang/src/alice/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | 8 | "github.com/justinas/alice" 9 | ) 10 | 11 | type numberDumper int 12 | 13 | func (n numberDumper) ServeHTTP(w http.ResponseWriter, r *http.Request) { 14 | fmt.Fprintf(w, "Here's your number: %d\n", n) 15 | } 16 | 17 | func logger(h http.Handler) http.Handler { 18 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ 19 | log.Printf("%s requested %s", r.RemoteAddr, r.URL) 20 | h.ServeHTTP(w, r) 21 | }) 22 | } 23 | 24 | type headerSetter struct { 25 | key, val string 26 | handler http.Handler 27 | } 28 | 29 | func (hs headerSetter) ServeHTTP(w http.ResponseWriter, r *http.Request) { 30 | w.Header().Set(hs.key, hs.val) 31 | hs.handler.ServeHTTP(w, r) 32 | } 33 | 34 | func newHeaderSetter(key, val string) func(http.Handler) http.Handler { 35 | return func(h http.Handler) http.Handler{ 36 | return headerSetter{key, val, h} 37 | } 38 | } 39 | func main() { 40 | h := http.NewServeMux() 41 | 42 | h.Handle("/one", numberDumper(1)) 43 | h.Handle("/two", numberDumper(2)) 44 | h.Handle("/three", numberDumper(3)) 45 | h.Handle("/four", numberDumper(4)) 46 | 47 | fiveHS := newHeaderSetter("X-FIVE", "the best number") 48 | h.Handle("/five", fiveHS(numberDumper(5))) 49 | 50 | h.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) { 51 | w.WriteHeader(404) 52 | fmt.Fprintln(w, "That's not a supported number!") 53 | }) 54 | 55 | chain := alice.New( 56 | newHeaderSetter("X-FOO", "BAR"), 57 | newHeaderSetter("X-BAR", "BUZ"), 58 | logger, 59 | ).Then(h) 60 | 61 | err := http.ListenAndServe(":9999", chain) 62 | log.Fatal(err) 63 | } 64 | -------------------------------------------------------------------------------- /learning_golang/src/ast/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/importer" 7 | "go/parser" 8 | "go/token" 9 | "go/types" 10 | "log" 11 | "reflect" 12 | ) 13 | // This example shows to a Go program can parse itself into an AST tree and 14 | // to infer types of nodes (expressions) in this AST tree. 15 | 16 | const ( 17 | kPath = "./" 18 | ) 19 | 20 | func main() { 21 | fset := token.NewFileSet() 22 | 23 | pkgs, e := parser.ParseDir(fset, kPath, nil, 0) 24 | if e != nil { 25 | log.Fatal(e) 26 | return 27 | } 28 | 29 | astf := make([]*ast.File, 0) 30 | for _, pkg := range pkgs{ 31 | fmt.Printf("package %v\n", pkg.Name) 32 | for fn, f := range pkg.Files{ 33 | fmt.Printf("file %v\n", fn) 34 | astf = append(astf, f) 35 | } 36 | } 37 | config := &types.Config{ 38 | Error: func(e error){ 39 | fmt.Println(e) 40 | }, 41 | Importer: importer.Default(), 42 | } 43 | info := types.Info{ 44 | Types: make(map[ast.Expr]types.TypeAndValue), 45 | Defs: make(map[*ast.Ident]types.Object), 46 | Uses: make(map[*ast.Ident]types.Object), 47 | } 48 | pkg, e := config.Check(kPath, fset, astf, &info) 49 | if e!= nil{ 50 | fmt.Println(e) 51 | } 52 | fmt.Printf("types.Config.Check got %v\n", pkg.String()) 53 | for _, f:= range astf{ 54 | ast.Walk(&PrintASTVisitor{&info}, f) 55 | } 56 | } 57 | 58 | type PrintASTVisitor struct{ 59 | info *types.Info 60 | } 61 | 62 | func (v *PrintASTVisitor) Visit(node ast.Node) ast.Visitor { 63 | if node != nil { 64 | fmt.Printf("%s", reflect.TypeOf(node).String()) 65 | switch node.(type) { 66 | case ast.Expr: 67 | t := v.info.TypeOf(node.(ast.Expr)) 68 | if t != nil { 69 | fmt.Printf(": %s", t.String()) 70 | } 71 | } 72 | fmt.Println() 73 | } 74 | return v 75 | } 76 | -------------------------------------------------------------------------------- /learning_golang/src/bits/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/nareix/bits" 8 | ) 9 | 10 | func main() { 11 | writer, _ := os.Create("test.bin") 12 | w := &bits.Writer{ 13 | W: writer, 14 | } 15 | err := w.WriteBits(0x22, 4) 16 | if err != nil{ 17 | panic(err) 18 | } 19 | err = w.WriteBits64(0x22, 4) 20 | n, err := w.Write([]byte{0x11, 0x22, 0x33, 0x44}) 21 | if err != nil { 22 | panic(err) 23 | } 24 | fmt.Printf("write %d bytes\n", n) 25 | err = w.FlushBits() 26 | 27 | reader, _ := os.Open("test.bin") 28 | r := &bits.Reader{ 29 | R: reader, 30 | } 31 | u32, _ := r.ReadBits(4) 32 | fmt.Printf("u32: %v\n", u32) 33 | u64, _ := r.ReadBits64(4) 34 | fmt.Printf("u64: %v\n", u64) 35 | p := make([]byte, 4) 36 | n, err = r.Read(p) 37 | if err != nil { 38 | panic(err) 39 | } 40 | fmt.Printf("byte %d: %v\n", n, p) 41 | } 42 | -------------------------------------------------------------------------------- /learning_golang/src/bolt/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/boltdb/bolt" 8 | ) 9 | 10 | var world = []byte("world") 11 | 12 | func main() { 13 | db, err := bolt.Open("bolt.db", 0644, nil) 14 | if err != nil { 15 | log.Fatal(err) 16 | } 17 | defer db.Close() 18 | 19 | key := []byte("hello") 20 | value := []byte("Hello World!") 21 | err = db.Update(func(tx *bolt.Tx) error { 22 | bucket, err := tx.CreateBucketIfNotExists(world) 23 | if err != nil { 24 | return err 25 | } 26 | err = bucket.Put(key, value) 27 | if err != nil{ 28 | return err 29 | } 30 | return nil 31 | }) 32 | if err != nil{ 33 | log.Fatal(err) 34 | } 35 | 36 | err = db.View(func(tx *bolt.Tx) error{ 37 | bucker := tx.Bucket(world) 38 | if bucket == nil { 39 | return fmt.Errorf("Bucket %q not found!", world) 40 | } 41 | val := bucket.Get(key) 42 | fmt.Println(string(val)) 43 | return nil 44 | }) 45 | if err != nil{ 46 | log.Fatal(err) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /learning_golang/src/bytes/reader_buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "io" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | buf := bytes.NewBufferString("R29waGVycyBydWxlIQ==") 12 | dec := base64.NewDecoder(base64.StdEncoding, buf) 13 | io.Copy(os.Stdout, dec) 14 | } 15 | -------------------------------------------------------------------------------- /learning_golang/src/bytes/write_buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | var b bytes.Buffer 11 | b.Write([]byte("Hello ")) 12 | fmt.Println(&b) 13 | fmt.Fprintf(&b, "World!\n") 14 | fmt.Println(&b) 15 | b.WriteTo(os.Stdout) 16 | } 17 | -------------------------------------------------------------------------------- /learning_golang/src/cache/memory.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/koding/cache" 8 | ) 9 | 10 | func main() { 11 | cache := cache.NewMemoryWithTTL(3 * time.Second) 12 | cache.StartGC(time.Second * 3) 13 | time.Sleep(3 * time.Second) 14 | cache.Set("test_key", "test_data") 15 | 16 | data, err := cache.Get("test_key") 17 | fmt.Println(data, err) 18 | 19 | time.Sleep(2 * time.Second) 20 | 21 | data, err = cache.Get("test_key") 22 | fmt.Println(data, err) 23 | time.Sleep(2 * time.Second) 24 | 25 | data, err = cache.Get("test_key") 26 | fmt.Println(data, err) 27 | } 28 | -------------------------------------------------------------------------------- /learning_golang/src/call_by_funcname/call_by_funcname.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | import ( 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // 计算器程序 函数按名称调用 10 | 11 | /* 12 | 最主要的是根据函数所在的结构体对象根据函数名称获取函数值, 13 | 即通过reflect.TypeOf(calc).MethodByName(funcName) 14 | 来获取函数的值,然后再使用[]reflect.Value来组装函数调用所需要的参数, 15 | 其中最重要的是params[0]必须是函数所在结构体对象的值,其他的则为对应函数的参数了。 16 | 最后使用fn.Func.Call方法调用函数即可。 17 | */ 18 | 19 | var opFuncs = map[string]string{ 20 | "+": "Add", 21 | "-": "Minus", 22 | "*": "Multi", 23 | "/": "Divide", 24 | } 25 | 26 | type Calculator struct { 27 | } 28 | 29 | func (this *Calculator) Add(a, b int) int { 30 | return a + b 31 | } 32 | 33 | func (this *Calculator) Minus(a, b int) int { 34 | return a - b 35 | } 36 | 37 | func (this *Calculator) Multi(a, b int) int { 38 | return a * b 39 | } 40 | 41 | func (this *Calculator) Divide(a, b int) int { 42 | return a / b 43 | } 44 | 45 | func main() { 46 | var a int = 10 47 | var b int = 20 48 | 49 | calc := &Calculator{} 50 | for funcOp, funcName := range opFuncs { 51 | fn, _ := reflect.TypeOf(calc).MethodByName(funcName) 52 | 53 | params := make([]reflect.Value, 3) 54 | params[0] = reflect.ValueOf(calc) 55 | params[1] = reflect.ValueOf(a) 56 | params[2] = reflect.ValueOf(b) 57 | v := fn.Func.Call(params) 58 | 59 | fmt.Println(fmt.Sprintf("%d %s %d = %d", a, funcOp, b, v[0].Int())) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /learning_golang/src/catena/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "github.com/codemodus/catena" 6 | ) 7 | 8 | func firstWapper(hr http.Handler) http.Handler { 9 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){ 10 | _, _ = w.Write([]byte("1")) 11 | hr.ServeHTTP(w, r) 12 | _, _ = w.Write([]byte("1")) 13 | }) 14 | } 15 | 16 | func endHandler(w http.ResponseWriter, r *http.Request) { 17 | _, _ = w.Write([]byte("end")) 18 | return 19 | } 20 | 21 | func main() { 22 | cat0 := catena.New(firstWapper) 23 | sm := http.NewServeMux() 24 | sm.Handle("/hello", cat0.EndFn(endHandler)) 25 | sm.ServeHTTP 26 | } 27 | -------------------------------------------------------------------------------- /learning_golang/src/cgo/callback/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | extern void my_callback(void*); 5 | static void my_job(void *p) { 6 | my_callback(p); 7 | } 8 | */ 9 | import ( 10 | "C" 11 | "unsafe" 12 | ) 13 | type message struct{ 14 | text string 15 | } 16 | 17 | func main(){ 18 | C.my_job(unsafe.Pointer(&message{ 19 | text: "I love golong", 20 | })) 21 | } 22 | 23 | func my_callback(p unsafe.Pointer) { 24 | println(((*message)(p)).text) 25 | } 26 | -------------------------------------------------------------------------------- /learning_golang/src/cgo/cfunc/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | int datspecialnumber() { 6 | return 2015; 7 | } 8 | */ 9 | 10 | import "C" 11 | import "fmt" 12 | 13 | func main() { 14 | fmt.Println(C.datspecialnumber()) 15 | } 16 | -------------------------------------------------------------------------------- /learning_golang/src/cgo/simple/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void my_puts(const char* msg) { 4 | printf("I'm thinking: %s\n", msg); 5 | } 6 | -------------------------------------------------------------------------------- /learning_golang/src/cgo/simple/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | extern void my_puts(const char*); 6 | */ 7 | import "C" 8 | import "unsafe" 9 | 10 | func main() { 11 | p := C.CString("Golang is awsome") 12 | defer C.free(unsafe.Pointer(p)) 13 | C.my_puts(p) 14 | } 15 | -------------------------------------------------------------------------------- /learning_golang/src/cipher/crypto/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/cipher" 5 | "crypto/des" 6 | "fmt" 7 | "math/rand" 8 | ) 9 | 10 | func makeRand(size int) []byte { 11 | r := make([]byte, size) 12 | for n := 0; n < len(r); n++ { 13 | r[n] = uint8(rand.Int() % 256) 14 | } 15 | return r 16 | } 17 | 18 | func main() { 19 | in := []byte("hello world") 20 | key := []byte("love go!") 21 | 22 | ci, _ := des.NewCipher(key[0:8]) 23 | fmt.Println(ci) 24 | iv := makeRand(8) 25 | fmt.Println(iv) 26 | enc := cipher.NewCBCEncrypter(ci, iv) 27 | fmt.Println(enc) 28 | cin := make([]byte, int(len(in)/des.BlockSize)*des.BlockSize+des.BlockSize) 29 | out := make([]byte, len(cin)) 30 | enc.CryptBlocks(out, cin) 31 | fmt.Printf("%X\n", iv) 32 | } 33 | -------------------------------------------------------------------------------- /learning_golang/src/cipher/crypto/rsa_keypair.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/rsa" 6 | "crypto/x509" 7 | "encoding/pem" 8 | "fmt" 9 | ) 10 | 11 | func main() { 12 | priv, err := rsa.GenerateKey(rand.Reader, 2016) 13 | if err != nil { 14 | fmt.Println(err) 15 | return 16 | } 17 | fmt.Println(priv) 18 | err = priv.Validate() 19 | if err != nil { 20 | fmt.Println("Validation failed.", err) 21 | } 22 | 23 | priv_der := x509.MarshalPKCS1PrivateKey(priv) 24 | 25 | priv_blk := pem.Block{ 26 | Type: "RSA PRIVATE KEY", 27 | Headers: nil, 28 | Bytes: priv_der, 29 | } 30 | 31 | priv_pem := string(pem.EncodeToMemory(&priv_blk)) 32 | fmt.Printf(priv_pem) 33 | 34 | pub := priv.PublicKey 35 | pub_der, err := x509.MarshalPKIXPublicKey(&pub) 36 | if err != nil { 37 | fmt.Println("Failed to get der format for PublicKey.", err) 38 | return 39 | } 40 | 41 | pub_blk := pem.Block{ 42 | Type: "PUBLIC KEY", 43 | Headers: nil, 44 | Bytes: pub_der, 45 | } 46 | pub_pem := string(pem.EncodeToMemory(&pub_blk)) 47 | fmt.Printf(pub_pem) 48 | } 49 | -------------------------------------------------------------------------------- /learning_golang/src/curl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/nareix/curl" 4 | import "time" 5 | import "log" 6 | import "net/http" 7 | import "fmt" 8 | 9 | func main() { 10 | 11 | 12 | req := curl.New("https://kernel.org/pub/linux/kernel/v4.x/linux-4.0.4.tar.xz") 13 | 14 | req.Method("POST") // can be PUT POST DELETE..... 15 | 16 | req.Header("MyHeader", "value") // custom header 17 | 18 | req.Headers = http.Header{ 19 | "User-Agent": {"mycurl/1.0"}, 20 | } 21 | 22 | ctrl := req.ControlDownload() 23 | go func(){ 24 | // control functions are thread safe 25 | ctrl.Stop() // Stop download 26 | ctrl.Pause() // Pause download 27 | ctrl.Resume() // Resume download 28 | }() 29 | 30 | req.DialTimeout(time.Second * 10) // TCP connection Timeout 31 | req.Timeout(time.Second * 30) 32 | 33 | req.Progress(func (p curl.ProgressStatus){ 34 | log.Println( 35 | "Stat", p.Stat, 36 | "speed", curl.PrettySpeedString(p.Speed), 37 | "len", curl.PrettySizeString(p.ContentLength), 38 | "got", curl.PrettySizeString(p.Size), 39 | "percent", p.Percent, 40 | "paused", p.Paused, 41 | ) 42 | }, time.Second) 43 | 44 | res, _ := req.Do() 45 | fmt.Println(res.HttpResponse) // related *http.Response struct 46 | log.Println(res.Body) // Body in string 47 | log.Println(res.StatusCode) // HTTP Status Code: 200,404,302 etc 48 | // log.Println(res.Hearders) // Reponse headers 49 | log.Println(res.DownloadStatus.AverageSpeed) // Average speed 50 | } 51 | -------------------------------------------------------------------------------- /learning_golang/src/md5/parallel.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/md5" 5 | "errors" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | "sort" 11 | "sync" 12 | ) 13 | 14 | // A result is the product of reading and summing a file using MD5. 15 | 16 | type result struc { 17 | path string 18 | sum [md5.Size]byte 19 | err error 20 | } 21 | 22 | // sumFiles starts goroutines to walk the directory tree at root and digest each 23 | // regular file. These goroutines send the results of the digests on the result 24 | // channel and send the result of the walk on the error channel. If done is 25 | // closed, sumFiles abandons its work. 26 | 27 | func sumFiles(done <-chan struct{}, root string)(<-chan result, <-chan error){ 28 | // For each regular file, start a goroutine that sums the file and sends 29 | // the result on c. Send the result of the walk on errc. 30 | c := make(chan result) 31 | errc := make(chan error, 1) 32 | go func(){ 33 | var wg sync.WaitGroup 34 | err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 35 | if err != nil{ 36 | return err 37 | } 38 | if !info.Mode().IsRegular(){ 39 | return nil 40 | } 41 | wg.Add(1) 42 | go func () { 43 | data, err := ioutil.ReadFile(path) 44 | select { 45 | case c<- result{path, md5.Sum(data), err}: 46 | case <-done: 47 | } 48 | wg.Done() 49 | }() 50 | select{ 51 | case <-done: 52 | reutrn errors.New("Walk canceled") 53 | default: 54 | return nil 55 | } 56 | }) 57 | go func(){ 58 | wg.Wait() 59 | close(c) 60 | }() 61 | errc <-err 62 | }() 63 | return c, errc 64 | } 65 | 66 | // MD5All reads all the files in the file tree rooted at root and returns a map 67 | // from file path to the MD5 sum of the file's contents. If the directory walk 68 | // fails or any read operation fails, MD5All returns an error. In that case, 69 | // MD5All does not wait for inflight read operations to complete. 70 | 71 | func MD5All(root string) (map[string][md5.Size]byte, error) { 72 | // MD5All closes the done channel when it returns; it may do so before 73 | // receiving all the values from c and errc. 74 | done := make(chan struct{}) // HLdone 75 | defer close(done) // HLdone 76 | 77 | c, errc := sumFiles(done, root) // HLdone 78 | 79 | m := make(map[string][md5.Size]byte) 80 | for r := range c { // HLrange 81 | if r.err != nil { 82 | return nil, r.err 83 | } 84 | m[r.path] = r.sum 85 | } 86 | if err := <-errc; err != nil { 87 | return nil, err 88 | } 89 | return m, nil 90 | } 91 | 92 | func main() { 93 | // Calculate the MD5 sum of all files under the specified directory, 94 | // then print the results sorted by path name. 95 | m, err := MD5All(os.Args[1]) 96 | if err != nil { 97 | fmt.Println(err) 98 | return 99 | } 100 | var paths []string 101 | for path := range m { 102 | paths = append(paths, path) 103 | } 104 | sort.Strings(paths) 105 | for _, path := range paths { 106 | fmt.Printf("%x %s\n", m[path], path) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /learning_golang/src/md5/serial.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "sort" 10 | ) 11 | 12 | 13 | // MD5All reads all the files in the file tree rooted at root and returns a map 14 | // from file path to the MD5 sum of the file's contents. If the directory walk 15 | // fails or any read operation fails, MD5All returns an error. 16 | 17 | func MD5All(root string) (map[string][md5.Size]byte, error) { 18 | m := make(map[string][md5.Size]byte) 19 | err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 20 | if err != nil{ 21 | return err 22 | } 23 | if !info.Mode().IsRegular(){ 24 | return nil 25 | } 26 | data, err := ioutil.ReadFile(path) 27 | if err != nil { 28 | return nil 29 | } 30 | m[path] = md5.Sum(data) 31 | return nil 32 | }) 33 | if err != nil { 34 | return nil, err 35 | } 36 | return m, nil 37 | } 38 | 39 | func main() { 40 | // Calculate the MD5 sum of all files under the specified directory, 41 | // then print the results sorted by path name. 42 | m, err := MD5All(os.Args[1]) 43 | if err != nil { 44 | fmt.Println(err) 45 | return 46 | } 47 | 48 | var paths []string 49 | for path := range m{ 50 | paths = append(paths, path) 51 | } 52 | sort.String(paths) 53 | for _, path := range paths{ 54 | f,t.Printf("%x %s\n", m[path], path) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /learning_golang/src/shell_build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | time=`date '+%Y-%m-%d-%H:%M:%S'` 4 | version=`git log -1 --oneline` 5 | strip_version=${version// /-} 6 | go build -ldflags "-X main.time='${time}' -X main.version='${strip_version}'" 7 | -------------------------------------------------------------------------------- /learning_golang/src/shell_build/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var ( 6 | version = "0.1.0" 7 | time = "1111" 8 | ) 9 | 10 | func main() { 11 | fmt.Println("version: ", version) 12 | fmt.Println("time: ", time) 13 | } 14 | -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | m := make(map[string]int) 9 | 10 | m["k1"] = 7 11 | m["k2"] = 13 12 | 13 | fmt.Println("map: ", m) 14 | 15 | delete(m, "k2") 16 | fmt.Println("map:", m) 17 | 18 | _, prs := m["k2"] 19 | fmt.Println("prs: ", prs) 20 | n := map[string]int{"foo": 1, "bar": 2} 21 | fmt.Println(n) 22 | } 23 | -------------------------------------------------------------------------------- /method.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type rect struct { 8 | width, height int 9 | } 10 | 11 | func (r *rect) area() int { //地址拷贝 12 | return r.width * r.height 13 | } 14 | 15 | func (r rect) perim() int { // 值拷贝 16 | return 2*r.width + 2*r.height 17 | } 18 | 19 | func (r *rect) padd(a int) int { //方法不能有多个返回值, 函数可以有多个返回值 20 | fmt.Println("width: ", r.width) 21 | r.width += a 22 | return r.width 23 | } 24 | 25 | func (r rect) iadd(a int) int { 26 | fmt.Println("width: ", r.width) 27 | r.width += a 28 | return r.width // r.width 只是在这个范围中 被修改了, 实际struct中的 width是没有被修改的 29 | } 30 | 31 | func main() { 32 | r := rect{width: 10, height: 10} 33 | 34 | fmt.Println("area: ", r.area()) 35 | fmt.Println("perim:", r.perim()) 36 | rp := &r 37 | fmt.Println("area: ", rp.area()) 38 | fmt.Println("perim:", rp.perim()) 39 | 40 | a := 10 41 | fmt.Println("iadd: ", r.iadd(a)) 42 | fmt.Println("padd: ", r.padd(a)) 43 | fmt.Println("padd: ", r.padd(a)) 44 | 45 | } 46 | -------------------------------------------------------------------------------- /multipart-file-upload.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "mime/multipart" 9 | "net/http" 10 | "os" 11 | "path/filepath" 12 | ) 13 | 14 | func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { 15 | file, err := os.Open(path) 16 | if err != nil { 17 | return nil, err 18 | } 19 | defer file.Close() 20 | 21 | body := &bytes.Buffer{} 22 | writer := multipart.NewWriter(body) 23 | part, err := writer.CreateFormFile(paramName, filepath.Base(path)) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | _, err = io.Copy(part, file) 29 | 30 | for key, val := range params { 31 | _ = writer.WriteField(key, val) 32 | } 33 | 34 | err = writer.Close() 35 | if err != nil { 36 | return nil, err 37 | } 38 | return http.NewRequest("POST", uri, body) 39 | } 40 | 41 | func main() { 42 | path, _ := os.Getwd() 43 | path += "/test.pdf" 44 | extraParams := map[string]string{ 45 | "title": "My Document", 46 | "author": "Matt Aimonetti", 47 | "description": "A document with all the Go programming language secrets", 48 | } 49 | request, err := newfileUploadRequest("https://google.com/upload", extraParams, "file", "/tmp/doc.pdf") 50 | if err != nil { 51 | log.Fatal(err) 52 | } 53 | client := &http.Client{} 54 | resp, err := client.Do(request) 55 | if err != nil { 56 | log.Fatal(err) 57 | } else { 58 | body := &bytes.Buffer{} 59 | _, err := body.ReadFrom(resp.Body) 60 | if err != nil { 61 | log.Fatal(err) 62 | } 63 | resp.Body.Close() 64 | fmt.Println(resp.StatusCode) 65 | fmt.Println(resp.Header) 66 | fmt.Println(body) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /multiple-return-values.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func vals() (int, int) { 8 | return 3, 7 9 | } 10 | 11 | func main() { 12 | a, b := vals() 13 | fmt.Println(a) 14 | fmt.Println(b) 15 | } 16 | -------------------------------------------------------------------------------- /multiplexing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func fanIn(input1, input2 <-chan string) <-chan string { 9 | c := make(chan string) 10 | go func() { 11 | for { 12 | c <- <-input1 13 | } 14 | }() 15 | go func() { 16 | for { 17 | c <- <-input2 18 | } 19 | }() 20 | return c 21 | } 22 | 23 | func main() { 24 | c := fanIn(boring("Joe"), boring("Ann")) 25 | for i := 0; i < 10; i++ { 26 | fmt.Println(<-c) 27 | } 28 | fmt.Println("You're both boring; I'm leaving.") 29 | } 30 | 31 | func boring(msg string) <-chan string { 32 | c := make(chan string) 33 | go func() { 34 | for i := 0; ; i++ { 35 | c <- fmt.Sprintf("%s %d", msg, i) 36 | time.Sleep(time.Duration(1000) * time.Millisecond) 37 | } 38 | }() 39 | return c 40 | } 41 | -------------------------------------------------------------------------------- /mutex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "runtime" 7 | "sync" 8 | "sync/atomic" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | var state = make(map[int]int) 14 | var mutex = &sync.Mutex{} 15 | 16 | var ops int64 = 0 17 | 18 | for r := 0; r < 100; r++ { 19 | go func() { 20 | total := 0 21 | for { 22 | key := rand.Intn(5) 23 | mutex.Lock() 24 | total += state[key] 25 | mutex.Unlock() 26 | atomic.AddInt64(&ops, 1) 27 | runtime.Gosched() 28 | } 29 | }() 30 | } 31 | 32 | for w := 0; w < 10; w++ { 33 | go func() { 34 | for { 35 | key := rand.Intn(5) 36 | val := rand.Intn(100) 37 | mutex.Lock() 38 | state[key] = val 39 | mutex.Unlock() 40 | atomic.AddInt64(&ops, 1) 41 | runtime.Gosched() 42 | } 43 | }() 44 | } 45 | time.Sleep(time.Second) 46 | opsFinal := atomic.LoadInt64(&ops) 47 | fmt.Println("ops:", opsFinal) 48 | mutex.Lock() 49 | fmt.Println("state:", state) 50 | mutex.Unlock() 51 | } 52 | -------------------------------------------------------------------------------- /non-blocking-channel-operations.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | messages := make(chan string) 10 | signals := make(chan bool) 11 | 12 | go func() { 13 | messages <- "result" 14 | }() 15 | 16 | time.Sleep(time.Second * 1) 17 | 18 | msg := "hi" 19 | select { 20 | case messages <- msg: 21 | fmt.Println("sent message", msg) 22 | default: 23 | fmt.Println("no message sent") 24 | } 25 | select { 26 | case msg := <-messages: 27 | fmt.Println("received messages", msg) 28 | default: 29 | fmt.Println("no messages received") 30 | } 31 | 32 | select { 33 | case msg := <-messages: 34 | fmt.Println("received message", msg) 35 | case sig := <-signals: 36 | fmt.Println("received signal", sig) 37 | default: 38 | fmt.Println("no activity") 39 | } 40 | } 41 | 42 | // Basic sends and receives on channels are blocking. 43 | // However, we can use select with a default clause to 44 | // implement non-blocking sends, receives, and even non-blocking multi-way selects. 45 | -------------------------------------------------------------------------------- /number-parsing.go: -------------------------------------------------------------------------------- 1 | package main 2 | The built-in package strconv provides the number parsing. 3 | import "strconv" 4 | import "fmt" 5 | func main() { 6 | // With ParseFloat, this 64 tells how many bits of precision to parse. 7 | f, _ := strconv.ParseFloat("1.234", 64) 8 | fmt.Println(f) 9 | // For ParseInt, the 0 means infer the base from the string. 64 requires that the result fit in 64 bits. 10 | i, _ := strconv.ParseInt("123", 0, 64) 11 | fmt.Println(i) 12 | // ParseInt will recognize hex-formatted numbers. 13 | d, _ := strconv.ParseInt("0x1c8", 0, 64) 14 | fmt.Println(d) 15 | // A ParseUint is also available. 16 | u, _ := strconv.ParseUint("789", 0, 64) 17 | fmt.Println(u) 18 | // Atoi is a convenience function for basic base-10 int parsing. 19 | k, _ := strconv.Atoi("135") 20 | fmt.Println(k) 21 | // Parse functions return an error on bad input. 22 | _, e := strconv.Atoi("wat") 23 | fmt.Println(e) 24 | } -------------------------------------------------------------------------------- /orange-algorithms-go/array-simple-to-use.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} 9 | n := max(nums) 10 | fmt.Println(n) 11 | a := avg(nums) 12 | fmt.Println(a) 13 | ary := rev_array(nums) 14 | fmt.Println(ary) 15 | 16 | } 17 | 18 | func max(nums []int) int { 19 | m := nums[0] 20 | 21 | for _, num := range nums { 22 | if num > m { 23 | m = num 24 | } 25 | } 26 | return m 27 | } 28 | 29 | func avg(nums []int) int { 30 | n := len(nums) 31 | m := 0 32 | for _, num := range nums { 33 | m = m + num 34 | } 35 | avg := m / n 36 | return avg 37 | } 38 | 39 | func rev_array(nums []int) []int { 40 | l := len(nums) 41 | for i, _ := range nums { 42 | t := nums[i] 43 | nums[i] = nums[l-1-i] 44 | nums[l-1-i] = t 45 | } 46 | return nums 47 | } 48 | -------------------------------------------------------------------------------- /page_url.txt: -------------------------------------------------------------------------------- 1 | https://gobyexample.com/ -------------------------------------------------------------------------------- /panic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | 5 | func main() { 6 | panic("a problem") 7 | _, err := os.Create("/tmp/file") 8 | if err != nil { 9 | panic(err) 10 | } 11 | } 12 | 13 | // A common use of panic is to abort if a function returns an error value that we don’t know how to (or want to) handle. Here’s an example of panicking if we get an unexpected error when creating a new file. 14 | -------------------------------------------------------------------------------- /ping-pong.go: -------------------------------------------------------------------------------- 1 | package main 2 | import "fmt" 3 | 4 | func ping(pings chan<- string, msg string){ 5 | pings <- msg 6 | } 7 | 8 | func pong(pings <-chan string, pongs chan<- string){ 9 | msg := <-pings 10 | pongs <- msg 11 | } 12 | 13 | func main(){ 14 | pings := make(chan string, 1) 15 | pongs := make(chan string, 1) 16 | ping(pings, "passed message") 17 | pong(pings, pongs) 18 | fmt.Println(<- pongs) 19 | } 20 | -------------------------------------------------------------------------------- /pointer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func zeroval(ival int) { 8 | ival = 0 9 | } 10 | 11 | func zeroptr(iptr *int) { 12 | *iptr = 0 13 | } 14 | 15 | func main() { 16 | i := 1 17 | fmt.Println("initial:", i) 18 | zeroval(i) 19 | fmt.Println("zeroval:", i) 20 | 21 | zeroptr(&i) 22 | fmt.Println("zeroptr:", i) 23 | fmt.Println("pointer:", &i) //每一次都随机分配过 指针地址 24 | } 25 | -------------------------------------------------------------------------------- /pubsub.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "fmt" 5 | zmq "github.con/alecthomas/gozmq" 6 | "strings" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type Message struct { 12 | Type string 13 | Channel string 14 | Data string 15 | } 16 | 17 | // Client interface for both Redis and ZMQ pubsub clients 18 | type Client interface { 19 | Subscribe(channels ...interface{}) (err error) 20 | Unsubscribe(channels ...interface{}) (err error) 21 | Publish(channel string, message string) 22 | Receive() (message Message) 23 | } 24 | 25 | // Redis client - defines the underlying connection and pub-sub 26 | // connections, as well as a mutex for locking write access, 27 | // since this occurs from multiple goroutines. 28 | type RedisClient struct { 29 | conn redis.Conn 30 | redis.PubSubConn 31 | sync.Mutex 32 | } 33 | 34 | // ZMQ client - just defines the pub and sub ZMQ sockets. 35 | type ZMQClient struct { 36 | pub *zmq.Socket 37 | sub *zmq.Socket 38 | } 39 | 40 | // Returns a new Redis client. The underlying redigo package uses 41 | // Go's bufio package which will flush the connection when it contains 42 | // enough data to send, but we still need to set up some kind of timed 43 | // flusher, so it's done here with a goroutine. 44 | 45 | func NewRedisClient(host string) *RedisClient { 46 | host = fmt.Sprintf("%s:6379", host) 47 | conn, _ := redis.Dial("tcp", host) 48 | pubsub, _ := redis.Dial("tcp", host) 49 | client := RedisClient{conn, redis.PubSubConn{pubsub}, sync.Mutex{}} 50 | go func() { 51 | for { 52 | time.Sleep(200 * time.Millisecond) 53 | client.Lock() 54 | client.conn.Flush() 55 | client.Unlock() 56 | } 57 | }() 58 | return &client 59 | } 60 | 61 | func (client *RedisClient) Publish(channel, message string) { 62 | client.Lock() 63 | client.conn.Send("PUBLISH", channel, message) 64 | client.Unlock() 65 | } 66 | 67 | func (client *RedisClient) Receive() Message { 68 | switch message := client.PubSubConn.Receive().(type) { 69 | case redis.Message: 70 | return Message{"message", message.Channel, string(message.Data)} 71 | case redis.Subscription: 72 | return Message{message.Kind, message.Channel, string(message.Count)} 73 | } 74 | return Message{} 75 | } 76 | 77 | func NewZMQClient(host string) *ZMQClient { 78 | context, _ := zmq.NewContext() 79 | pub, _ := context.NewSocket(zmq.PUSH) 80 | pub.Connect(fmt.Sprintf("tcp://%s:%d", host, 5562)) 81 | sub, _ := context.NewSocket(zmq.SUB) 82 | sub.Connect(fmt.Sprintf("tcp://%s:%d", host, 5561)) 83 | return &ZMQClient{pub, sub} 84 | } 85 | 86 | func (client *ZMQClient) Subscribe(channels ...interface{}) error { 87 | for _, channel := range channels { 88 | client.sub.SetSockOptString(zmq.SUBSCRIBE, channel.(string)) 89 | } 90 | return nil 91 | } 92 | 93 | func (client *ZMQClient) Unsubscribe(channels ...interface{}) error { 94 | for _, channel := range channels { 95 | client.sub.SetSockOptString(zmq.UNSUBSCRIBE, channel.(string)) 96 | } 97 | return nil 98 | } 99 | 100 | func (client *ZMQClient) Publish(channel, message string) { 101 | client.pub.Send([]byte(channel+" "+message), 0) 102 | } 103 | 104 | func (client *ZMQClient) Receive() Message { 105 | message, _ := client.sub.Recv(0) 106 | parts := string.SplitN(string(message), " ", 2) 107 | return Message{Type: "message", Channel: parts[0], Data: parts[1]} 108 | } 109 | -------------------------------------------------------------------------------- /random-numbers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | fmt.Print(rand.Intn(100), ",") 11 | fmt.Print(rand.Intn(100)) 12 | fmt.Println() 13 | 14 | fmt.Println(rand.Float64()) 15 | 16 | fmt.Print((rand.Float64()*5)+5, ",") 17 | fmt.Print((rand.Float64() * 5) + 5) 18 | fmt.Println() 19 | 20 | s1 := rand.NewSource(time.Now().UnixNano()) 21 | r1 := rand.New(s1) 22 | 23 | fmt.Print(r1.Intn(100), ",") 24 | fmt.Print(r1.Intn(100)) 25 | fmt.Println() 26 | // If you seed a source with the same number, it produces the same sequence of random numbers. 27 | s2 := rand.NewSource(42) 28 | r2 := rand.New(s2) 29 | fmt.Print(r2.Intn(100), ",") 30 | fmt.Print(r2.Intn(100)) 31 | fmt.Println() 32 | s3 := rand.NewSource(42) 33 | r3 := rand.New(s3) 34 | fmt.Print(r3.Intn(100), ",") 35 | fmt.Print(r3.Intn(100)) 36 | } 37 | 38 | // 81,87 39 | // 0.6645600532184904 40 | // 7.123187485356329,8.434115364335547 41 | // 0,28 42 | // 5,87 43 | // 5,87 44 | -------------------------------------------------------------------------------- /random.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | var channel chan int64 = make(chan int64, 32) 10 | 11 | func init() { 12 | go func() { 13 | var old int64 14 | for { 15 | o := rand.New(rand.NewSource(time.Now().UnixNano())).Int63() 16 | if old != o { 17 | old = o 18 | select { 19 | case channel <- o: 20 | } 21 | } 22 | } 23 | }() 24 | } 25 | 26 | func RandInt64() (r int64) { 27 | select { 28 | case rand := <-channel: 29 | r = rand 30 | } 31 | return 32 | } 33 | 34 | func main() { 35 | var n int64 36 | n = RandInt64() 37 | fmt.Println(n) 38 | } 39 | -------------------------------------------------------------------------------- /range-over-channels.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | queue := make(chan string, 2) 9 | queue <- "one" 10 | queue <- "two" // chan 在同一个GOroutine中 11 | close(queue) 12 | 13 | for elem := range queue { 14 | fmt.Println(elem) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /range.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | nums := []int{2, 3, 4} 9 | sum := 0 10 | for _, num := range nums { 11 | sum += num 12 | } 13 | fmt.Println("sum: ", sum) 14 | 15 | for i, num := range nums { 16 | sum += nums[i] 17 | if num == 3 { 18 | fmt.Println("index: ", i) 19 | } 20 | } 21 | kvs := map[string]string{"a": "apple", "b": "banana"} 22 | for k, v := range kvs { 23 | fmt.Println("%s-> %s\n", k, v) 24 | } 25 | for i, c := range "go" { 26 | fmt.Println(i, c) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rate-limiting.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | requests := make(chan int, 5) 10 | for i := 1; i <= 5; i++ { 11 | requests <- i 12 | } 13 | close(requests) 14 | 15 | limiter := time.Tick(time.Millisecond * 200) 16 | 17 | for req := range requests { 18 | <-limiter 19 | fmt.Println("requests", req, time.Now()) 20 | } 21 | 22 | burstyLimiter := make(chan time.Time, 3) 23 | 24 | for i := 0; i < 3; i++ { 25 | burstyLimiter <- time.Now() 26 | } 27 | 28 | go func() { 29 | for t := range time.Tick(time.Millisecond * 200) { 30 | burstyLimiter <- t 31 | } 32 | }() 33 | 34 | burstyRequests := make(chan int, 5) 35 | for i := 1; i <= 5; i++ { 36 | burstyRequests <- i 37 | } 38 | close(burstyRequests) 39 | for req := range burstyRequests { 40 | <-burstyLimiter 41 | fmt.Println("request", req, time.Now()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /reading-files.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | ) 10 | 11 | // Reading files requires checking most calls for errors. This helper will streamline our error checks below. 12 | func check(e error) { 13 | if e != nil { 14 | panic(e) 15 | } 16 | } 17 | 18 | func main() { 19 | // Perhaps the most basic file reading task is slurping a file’s entire contents into memory. 20 | dat, err := ioutil.ReadFile("/tmp/dat") 21 | check(err) 22 | fmt.Print(string(dat)) 23 | // You’ll often want more control over how and what parts of a file are read. For these tasks, start by Opening a file to obtain an os.File value. 24 | f, err := os.Open("/tmp/dat") 25 | check(err) 26 | // Read some bytes from the beginning of the file. Allow up to 5 to be read but also note how many actually were read. 27 | b1 := make([]byte, 5) 28 | n1, err := f.Read(b1) 29 | check(err) 30 | fmt.Printf("%d bytes: %s\n", n1, string(b1)) 31 | // You can also Seek to a known location in the file and Read from there. 32 | o2, err := f.Seek(6, 0) 33 | check(err) 34 | b2 := make([]byte, 2) 35 | n2, err := f.Read(b2) 36 | check(err) 37 | fmt.Printf("%d bytes @ %d: %s\n", n2, o2, string(b2)) 38 | 39 | // The io package provides some functions that may be helpful for file reading. For example, reads like the ones above can be more robustly implemented with ReadAtLeast 40 | o3, err := f.Seek(6, 0) 41 | check(err) 42 | b3 := make([]byte, 4) 43 | n3, err := io.ReadAtLeast(f, b3, 4) 44 | check(err) 45 | fmt.Printf("%d bytes @ %d: %s\n", n3, o3, string(b3)) 46 | // The bufio package implements a buffered reader that may be useful both for its efficiency with many small reads and because of the additional reading methods it provides./ 47 | r4 := bufio.NewReader(f) 48 | b4, err := r4.Peek(5) 49 | check(err) 50 | fmt.Printf("5 bytes: %s\n", string(b4)) 51 | defer f.Close() 52 | } 53 | -------------------------------------------------------------------------------- /real-life-concurrency-in-go.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | var urls = []string{ 10 | "http://www.hao123.com", 11 | "http://www.baidu.com", 12 | "https://ruby-china.org/", 13 | } 14 | 15 | type HttpResponse struct { 16 | url string 17 | response *http.Response 18 | err error 19 | } 20 | 21 | func asyncHttpGets(urls []string) []*HttpResponse { 22 | ch := make(chan *HttpResponse) 23 | responses := []*HttpResponse{} 24 | client := http.Client{} 25 | for _, url := range urls { 26 | go func(url string) { 27 | fmt.Printf("Fetching %s", url) 28 | resp, err := client.Get(url) 29 | ch <- &HttpResponse{url, resp, err} 30 | if err != nil && resp != nil && resp.StatusCode == http.StatusOK { 31 | resp.Body.Close() 32 | } 33 | }(url) 34 | } 35 | 36 | for { 37 | select { 38 | case r := <-ch: 39 | fmt.Printf("%s was fetched\n", r.url) 40 | if r.err != nil { 41 | fmt.Println("with an error", r.err) 42 | } 43 | responses = append(responses, r) 44 | if len(responses) == len(urls) { 45 | return responses 46 | } 47 | default: 48 | fmt.Printf(".") 49 | time.Sleep(50 * time.Millisecond) 50 | } 51 | } 52 | } 53 | 54 | func main() { 55 | results := asyncHttpGets(urls) 56 | for _, result := range results { 57 | if result != nil && result.response != nil { 58 | fmt.Printf("%s status: %s\n", result.url, 59 | result.response.Status) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /recursion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func fact(n int) int { 8 | if n == 0 { 9 | return 1 10 | } 11 | return n * fact(n-1) 12 | } 13 | 14 | func main() { 15 | fmt.Println(fact(7)) 16 | } 17 | -------------------------------------------------------------------------------- /regular-expressions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "regexp" 7 | ) 8 | 9 | func main() { 10 | // This tests whether a pattern matches a string. 11 | match, _ := regexp.MatchString("p([a-z]+)ch", "peach") 12 | fmt.Println(match) 13 | // Above we used a string pattern directly, but for other regexp tasks you’ll need to Compile an optimized Regexp struct. 14 | r, _ := regexp.Compile("p([a-z]+)ch") 15 | // Many methods are available on these structs. Here’s a match test like we saw earlier. 16 | fmt.Println(r.MatchString("peach")) 17 | // This finds the match for the regexp. 18 | fmt.Println(r.FindString("peach punch")) 19 | // This also finds the first match but returns the start and end indexes for the match instead of the matching text. 20 | fmt.Println(r.FindStringIndex("peach punch")) 21 | // The Submatch variants include information about both the whole-pattern matches and the submatches within those matches. For example this will return information for both p([a-z]+)ch and ([a-z]+). 22 | fmt.Println(r.FindStringSubmatch("peach punch")) 23 | // Similarly this will return information about the indexes of matches and submatches. 24 | fmt.Println(r.FindStringSubmatchIndex("peach punch")) 25 | // The All variants of these functions apply to all matches in the input, not just the first. For example to find all matches for a regexp. 26 | fmt.Println(r.FindAllString("peach punch pinch", -1)) 27 | // These All variants are available for the other functions we saw above as well. 28 | fmt.Println(r.FindAllStringSubmatchIndex("peach punch pinch", -1)) 29 | // Providing a non-negative integer as the second argument to these functions will limit the number of matches. 30 | fmt.Println(r.FindAllString("peach punch pinch", 2)) 31 | // Our examples above had string arguments and used names like MatchString. We can also provide []byte arguments and drop String from the function name. 32 | fmt.Println(r.Match([]byte("peach"))) 33 | // When creating constants with regular expressions you can use the MustCompile variation of Compile. A plain Compile won’t work for constants because it has 2 return values. 34 | r = regexp.MustCompile("p([a-z]+)ch") 35 | fmt.Println(r) 36 | // The regexp package can also be used to replace subsets of strings with other values. 37 | fmt.Println(r.ReplaceAllString("a peach", "")) 38 | // The Func variant allows you to transform matched text with a given function. 39 | in := []byte("a peach") 40 | out := r.ReplaceAllFunc(in, bytes.ToUpper) 41 | fmt.Println(string(out)) 42 | } 43 | -------------------------------------------------------------------------------- /select.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c1 := make(chan string) 10 | c2 := make(chan string) 11 | 12 | go func() { 13 | time.Sleep(time.Second * 1) 14 | c1 <- "one" 15 | }() 16 | go func() { 17 | time.Sleep(time.Second * 2) 18 | c2 <- "two" 19 | }() 20 | 21 | for i := 0; i < 2; i++ { 22 | select { 23 | case msg1 := <-c1: 24 | fmt.Println("received", msg1) 25 | case msg2 := <-c2: 26 | fmt.Println("received", msg2) 27 | } 28 | } 29 | 30 | // Each channel will receive a value after some amount of time, 31 | // to simulate e.g. blocking RPC operations executing in concurrent goroutines. 32 | // We’ll use select to await both of these values simultaneously, 33 | // printing each one as it arrives.We receive the values "one" and then "two" as expected 34 | // Note that the total execution time is only ~2 seconds since both the 1 and 2 second Sleeps execute concurrently. -------------------------------------------------------------------------------- /sha1-hashes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha1" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | s := "sha1 this string" 10 | // The pattern for generating a hash is sha1.New(), sha1.Write(bytes), then sha1.Sum([]byte{}). Here we start with a new hash. 11 | h := sha1.New() 12 | // Write expects bytes. If you have a string s, use []byte(s) to coerce it to bytes. 13 | // This gets the finalized hash result as a byte slice. The argument to Sum can be used to append to an existing byte slice: it usually isn’t needed. 14 | h.Write([]byte(s)) 15 | 16 | bs := h.Sum(nil) 17 | 18 | fmt.Println(s) 19 | fmt.Printf("%x\n", bs) 20 | } 21 | -------------------------------------------------------------------------------- /signals.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "os" 5 | import "os/signal" 6 | import "syscall" 7 | 8 | // Sometimes we’d like our Go programs to intelligently handle Unix signals. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool to stop processing input if it receives a SIGINT. Here’s how to handle signals in Go with channels. 9 | 10 | func main() { 11 | // Go signal notification works by sending os.Signal values on a channel. We’ll create a channel to receive these notifications (we’ll also make one to notify us when the program can exit). 12 | sigs := make(chan os.Signal, 1) 13 | done := make(chan bool, 1) 14 | // signal.Notify registers the given channel to receive notifications of the specified signals. 15 | signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) 16 | // This goroutine executes a blocking receive for signals. When it gets one it’ll print it out and then notify the program that it can finish. 17 | go func() { 18 | sig := <-sigs 19 | fmt.Println() 20 | fmt.Println(sig) 21 | done <- true 22 | }() 23 | // The program will wait here until it gets the expected signal (as indicated by the goroutine above sending a value on done) and then exit. 24 | fmt.Println("awaiting signal") 25 | <-done 26 | fmt.Println("exiting") 27 | } 28 | 29 | // When we run this program it will block waiting for a signal. By typing ctrl-C (which the terminal shows as ^C) we can send a SIGINT signal, causing the program to print interrupt and then exit. 30 | // $ go run signals.go 31 | // awaiting signal 32 | // ^C 33 | // interrupt 34 | // exiting 35 | -------------------------------------------------------------------------------- /simple-web-server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/", Cookie) // 1. http.HandleFunc 11 | 12 | http.ListenAndServe(":9090", nil) //2. http.ListenAndServe 13 | } 14 | 15 | func Cookie(w http.ResponseWriter, r *http.Request) { //3. the function in HandleFunc 16 | ck := &http.Cookie{ 17 | Name: "myCookie", 18 | Value: "hello", 19 | Path: "/", 20 | Domain: "localhost", 21 | MaxAge: 120, 22 | } 23 | 24 | http.SetCookie(w, ck) 25 | ck2, err := r.Cookie("uuid") 26 | 27 | if err != nil { 28 | io.WriteString(w, err.Error()) 29 | fmt.Println("The cookie is not exit") 30 | return 31 | } 32 | 33 | io.WriteString(w, ck2.Value) 34 | } 35 | -------------------------------------------------------------------------------- /slice.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | s := make([]string, 3) 9 | fmt.Println("emp: ", s) 10 | s[0] = "a" 11 | s[1] = "b" 12 | s[2] = "c" 13 | fmt.Println(cap(s)) 14 | fmt.Println(s) 15 | 16 | s = append(s, "d") 17 | s = append(s, "e", "f") 18 | fmt.Println(cap(s)) 19 | fmt.Println(s) 20 | 21 | c := make([]string, len(s)) 22 | copy(c, s) 23 | fmt.Println("cpy: ", c) 24 | 25 | l := s[1:] 26 | fmt.Println(l) 27 | } 28 | -------------------------------------------------------------------------------- /sorting-by-functions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | type ByLength []string 9 | 10 | func (s ByLength) Len() int { 11 | return len(s) 12 | } 13 | 14 | func (s ByLength) Swap(i, j int) { 15 | s[i], s[j] = s[j], s[i] 16 | } 17 | 18 | func (s ByLength) Less(i, j int) bool { 19 | return len(s[i]) < len(s[j]) 20 | } 21 | 22 | func main() { 23 | fruits := []string{"peach", "banana", "kiwi"} 24 | fmt.Println(ByLength(fruits)) 25 | sort.Sort(ByLength(fruits)) 26 | fmt.Println(fruits) 27 | } 28 | 29 | // We implement sort.Interface - Len, Less, and Swap - on our type so we can use the sort package’s 30 | // generic Sort function. Len and Swap will usually be similar across types and Less will hold the actual 31 | // custom sorting logic. In our case we want to sort in order of increasing string length, 32 | // so we use len(s[i]) and len(s[j]) here. 33 | -------------------------------------------------------------------------------- /sorting.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "sort" 5 | 6 | func main() { 7 | strs := []string{"c", "a", "b"} 8 | sort.Strings(strs) 9 | fmt.Println("Strings: ", strs) 10 | 11 | ints := []int{7, 2, 6} 12 | sort.Ints(ints) 13 | fmt.Println("Ints: ", ints) 14 | 15 | s := sort.IntsAreSorted(ints) 16 | fmt.Println("Sorted: ", s) 17 | } 18 | -------------------------------------------------------------------------------- /spawning-processes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os/exec" 7 | ) 8 | 9 | func main() { 10 | dateCmd := exec.Command("date") 11 | 12 | dateOut, err := dateCmd.Output() 13 | if err != nil { 14 | panic(err) 15 | } 16 | fmt.Println("> date") 17 | fmt.Println(string(dateOut)) 18 | 19 | grepCmd := exec.Command("grep", "hello") 20 | 21 | grepIn, _ := grepCmd.StdinPipe() 22 | grepOut, _ := grepCmd.StdoutPipe() 23 | grepCmd.Start() 24 | grepIn.Write([]byte("hello grep\ngoodbye grep")) 25 | grepIn.Close() 26 | grepBytes, _ := ioutil.ReadAll(grepOut) 27 | grepCmd.Wait() 28 | // We ommited error checks in the above example, but you could use the usual if err != nil pattern for all of them. We also only collect the StdoutPipe results, but you could collect the StderrPipe in exactly the same way. 29 | fmt.Println("> grep hello") 30 | fmt.Println(string(grepBytes)) 31 | // Note that when spawning commands we need to provide an explicitly delineated command and argument array, vs. being able to just pass in one command-line string. If you want to spawn a full command with a string, you can use bash’s -c option: 32 | lsCmd := exec.Command("bash", "-c", "ls -a -l -h") 33 | lsOut, err := lsCmd.Output() 34 | if err != nil { 35 | panic(err) 36 | } 37 | fmt.Println("> ls -a -l -h") 38 | fmt.Println(string(lsOut)) 39 | } 40 | -------------------------------------------------------------------------------- /string-formatting.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "os" 5 | 6 | type point struct { 7 | x, y int 8 | } 9 | 10 | func main() { 11 | // Go offers several printing “verbs” designed to format general Go values. For example, this prints an instance of our point struct. 12 | p := point{1, 2} 13 | fmt.Printf("%v\n", p) 14 | // If the value is a struct, the %+v variant will include the struct’s field names. 15 | fmt.Printf("%+v\n", p) 16 | // The %#v variant prints a Go syntax representation of the value, i.e. the source code snippet that would produce that value. 17 | fmt.Printf("%#v\n", p) 18 | // To print the type of a value, use %T. 19 | fmt.Printf("%T\n", p) 20 | // Formatting booleans is straight-forward. 21 | fmt.Printf("%t\n", true) 22 | // There are many options for formatting integers. Use %d for standard, base-10 formatting. 23 | fmt.Printf("%d\n", 123) 24 | // This prints a binary representation. 25 | fmt.Printf("%b\n", 14) 26 | // This prints the character corresponding to the given integer. 27 | fmt.Printf("%c\n", 33) 28 | // %x provides hex encoding. 29 | fmt.Printf("%x\n", 456) 30 | // There are also several formatting options for floats. For basic decimal formatting use %f. 31 | fmt.Printf("%f\n", 78.9) 32 | // %e and %E format the float in (slightly different versions of) scientific notation. 33 | fmt.Printf("%e\n", 123400000.0) 34 | fmt.Printf("%E\n", 123400000.0) 35 | // For basic string printing use %s. 36 | fmt.Printf("%s\n", "\"string\"") 37 | // To double-quote strings as in Go source, use %q. 38 | fmt.Printf("%q\n", "\"string\"") 39 | // As with integers seen earlier, %x renders the string in base-16, with two output characters per byte of input. 40 | fmt.Printf("%x\n", "hex this") 41 | // To print a representation of a pointer, use %p. 42 | fmt.Printf("%p\n", &p) 43 | // When formatting numbers you will often want to control the width and precision of the resulting figure. To specify the width of an integer, use a number after the % in the verb. By default the result will be right-justified and padded with spaces. 44 | fmt.Printf("|%6d|%6d|\n", 12, 345) 45 | 46 | fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45) 47 | // To left-justify, use the - flag. 48 | fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45) 49 | // You may also want to control width when formatting strings, especially to ensure that they align in table-like output. For basic right-justified width. 50 | fmt.Printf("|%6s|%6s|\n", "foo", "b") 51 | // To left-justify use the - flag as with numbers. 52 | fmt.Printf("|%-6s|%-6s|\n", "foo", "b") 53 | // So far we’ve seen Printf, which prints the formatted string to os.Stdout. Sprintf formats and returns a string without printing it anywhere. 54 | s := fmt.Sprintf("a %s", "string") 55 | fmt.Println(s) 56 | // You can format+print to io.Writers other than os.Stdout using Fprintf. 57 | fmt.Fprintf(os.Stderr, "an %s\n", "error") 58 | } 59 | 60 | // {1 2} 61 | // {x:1 y:2} 62 | // main.point{x:1, y:2} 63 | // main.point 64 | // true 65 | // 123 66 | // 1110 67 | // ! 68 | // 1c8 69 | // 78.900000 70 | // 1.234000e+08 71 | // 1.234000E+08 72 | // "string" 73 | // "\"string\"" 74 | // 6865782074686973 75 | // 0x42135100 76 | // | 12| 345| 77 | // | 1.20| 3.45| 78 | // |1.20 |3.45 | 79 | // | foo| b| 80 | // |foo |b | 81 | // a string 82 | // an error 83 | -------------------------------------------------------------------------------- /string-functions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ss "strings" 6 | ) 7 | 8 | var p = fmt.Println 9 | 10 | func main() { 11 | p("Contains: ", ss.Contains("test", "es")) 12 | p("Count: ", ss.Count("test", "t")) 13 | p("HasPrefix: ", ss.HasPrefix("test", "te")) 14 | p("Index: ", ss.HasSuffix("test", "st")) 15 | p("Join: ", ss.Join([]string{"a", "b"}, "-")) 16 | p("Repeat: ", ss.Repeat("a", 5)) 17 | p("Replace: ", ss.Replace("foo", "o", "0", -1)) 18 | p("Replace: ", ss.Replace("foo", "o", "0", 1)) 19 | p("Split: ", ss.Split("a-b-c-d-e", "-")) 20 | p("ToLower: ", ss.ToLower("TEST")) 21 | p("ToUpper: ", ss.ToUpper("test")) 22 | p() 23 | p("Len: ", len("hello")) 24 | p("Char:", "hello"[1]) 25 | } 26 | -------------------------------------------------------------------------------- /sum-goroutines.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | var c = make(chan int) 10 | 11 | func main() { 12 | start := time.Now().UnixNano() 13 | fmt.Println(runtime.NumCPU()) 14 | runtime.GOMAXPROCS(runtime.NumCPU()) 15 | mysum := 0 16 | max, num := 10000, 10 17 | for i := 0; i < max; i++ { 18 | go sum((max/num)*i+1, (max/num)*(i+1), i) 19 | } 20 | for i := 0; i < num; i++ { 21 | mysum = mysum + <-c 22 | } 23 | fmt.Println("sum:", mysum) 24 | fmt.Println("take times is : ", (time.Now().UnixNano() - start)) 25 | } 26 | 27 | func sum(min, max, number int) { 28 | s := 0 29 | for i := min; i <= max; i++ { 30 | s = s + 1 31 | } 32 | c <- s 33 | } 34 | -------------------------------------------------------------------------------- /switch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | i := 2 10 | fmt.Println("write ", i, " as ") 11 | switch i { 12 | case 1: 13 | fmt.Println("one") 14 | case 2: 15 | fmt.Println("two") 16 | case 3: 17 | fmt.Println("three") 18 | } 19 | 20 | switch time.Now().Weekday() { 21 | case time.Saturday, time.Sunday: 22 | fmt.Println("it's the weekend") 23 | default: 24 | fmt.Println("it's a weekday") 25 | } 26 | 27 | t := time.Now() 28 | switch { 29 | case t.Hour() < 12: 30 | fmt.Println("it is before noon") 31 | default: 32 | fmt.Println("it is after noon") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tickers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | ticker := time.NewTicker(time.Millisecond * 500) 10 | go func() { 11 | for t := range ticker.C { 12 | fmt.Println("Tick at", t) 13 | } 14 | }() 15 | 16 | time.Sleep(time.Millisecond * 1600) 17 | ticker.Stop() 18 | fmt.Println("Ticker stopped") 19 | } 20 | 21 | //Tickers use a similar mechanism to timers: a channel that is sent values. 22 | // Here we’ll use the range builtin on the channel to iterate over the values as they arrive every 500ms. 23 | //Tickers can be stopped like timers. Once a ticker is stopped it won’t receive any 24 | // more values on its channel. We’ll stop ours after 1600ms 25 | -------------------------------------------------------------------------------- /time-formatting-parsing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | p := fmt.Println 10 | 11 | t := time.Now() 12 | p(t.Format(time.RFC3339)) 13 | 14 | t1, e := time.Passe( 15 | time.RFC3339, 16 | "2012-11-01T22:08:41+00:00") 17 | p(t1) 18 | p(t.Format("3:04PM")) 19 | p(t.Format("Mon Jan _2 15:04:05 2006")) 20 | p(t.Format("2006-01-02T15:04:05.999999-07:00")) 21 | form := "3 04 PM" 22 | t2, e := time.Parse(form, "8 41 PM") 23 | p(t2) 24 | // For purely numeric representations you can also use standard string formatting with the extracted components of the time value. 25 | fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n", 26 | t.Year(), t.Month(), t.Day(), 27 | t.Hour(), t.Minute(), t.Second()) 28 | // Parse will return an error on malformed input explaining the parsing problem. 29 | ansic := "Mon Jan _2 15:04:05 2006" 30 | _, e = time.Parse(ansic, "8:41PM") 31 | p(e) 32 | } 33 | 34 | // 2014-04-15T18:00:15-07:00 35 | // 2012-11-01 22:08:41 +0000 +0000 36 | // 6:00PM 37 | // Tue Apr 15 18:00:15 2014 38 | // 2014-04-15T18:00:15.161182-07:00 39 | // 0000-01-01 20:41:00 +0000 UTC 40 | // 2014-04-15T18:00:15-00:00 41 | // parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": ... 42 | -------------------------------------------------------------------------------- /time_sub.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main { 9 | t := time.Now() 10 | loc, _ := time.LoadLocation("Asia/Shanghai") 11 | tm, _ := time.ParseInLocation("20060102150405", timestamp, loc) // 获得准确本地时间的方法 12 | x := t.Sub(tm).Minutes() 13 | fmt.Println(t) 14 | fmt.Println(tm) 15 | fmt.Println(x) 16 | } -------------------------------------------------------------------------------- /timeout_boring.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c := boring("Joe") 10 | for { 11 | select { 12 | case s := <-c: 13 | fmt.Println(s) 14 | case <-time.After(1 * time.Second): 15 | fmt.Println("You're too slow.") 16 | return 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /timeouts.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | c1 := make(chan string, 1) 10 | go func() { 11 | time.Sleep(time.Second * 2) 12 | c1 <- "result 1" 13 | }() 14 | 15 | select { 16 | case res := <-c1: 17 | fmt.Println(res) 18 | case <-time.After(time.Second * 1): 19 | fmt.Println("timeout 1") 20 | } 21 | 22 | c2 := make(chan string, 1) 23 | go func() { 24 | time.Sleep(time.Second * 2) 25 | c2 <- "result 2" 26 | }() 27 | select { 28 | case res := <-c2: 29 | fmt.Println(res) 30 | case <-time.After(time.Second * 3): 31 | fmt.Println("timeout 2") 32 | } 33 | } 34 | 35 | //Using this select timeout pattern requires communicating results over channels. This is a good idea in general because other important Go features are based on channels and select. 36 | -------------------------------------------------------------------------------- /timers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "time" 4 | import "fmt" 5 | 6 | func main() { 7 | timer1 := time.NewTimer(time.Second * 2) 8 | <-timer1.C 9 | fmt.Println("Timer 1 expired") 10 | timer2 := time.NewTimer(time.Second) 11 | go func() { 12 | <-timer2.C 13 | fmt.Println("Timer 2 expired") 14 | }() 15 | stop2 := timer2.Stop() 16 | if stop2 { 17 | fmt.Println("Timer 2 stopped") 18 | } 19 | } 20 | 21 | //We often want to execute Go code at some point in the future, or repeatedly at some interval. 22 | // Go’s built-in timer and ticker features make both of these tasks easy. We’ll look first at timers and then at tickers. 23 | //f you just wanted to wait, you could have used time.Sleep. One reason a timer may be useful is that you can cancel the timer before it expires. Here’s an example of that. 24 | -------------------------------------------------------------------------------- /times.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | p := fmt.Println 10 | // We’ll start by getting the current time. 11 | now := time.Now() 12 | p(now) 13 | // You can build a time struct by providing the year, month, day, etc. Times are always associated with a Location, i.e. time zone. 14 | then := time.Date( 15 | 2009, 11, 17, 20, 34, 58, 651387237, time.UTC) 16 | p(then) 17 | // You can extract the various components of the time value as expected. 18 | p(then.Year()) 19 | p(then.Month()) 20 | p(then.Day()) 21 | p(then.Hour()) 22 | p(then.Minute()) 23 | p(then.Second()) 24 | p(then.Nanosecond()) 25 | p(then.Location()) 26 | // The Monday-Sunday Weekday is also available. 27 | p(then.Weekday()) 28 | // These methods compare two times, testing if the first occurs before, after, or at the same time as the second, respectively. 29 | p(then.Before(now)) 30 | p(then.After(now)) 31 | p(then.Equal(now)) 32 | // The Sub methods returns a Duration representing the interval between two times. 33 | diff := now.Sub(then) 34 | p(diff) 35 | // We can compute the length of the duration in various units. 36 | p(diff.Hours()) 37 | p(diff.Minutes()) 38 | p(diff.Seconds()) 39 | p(diff.Nanoseconds()) 40 | // You can use Add to advance a time by a given duration, or with a - to move backwards by a duration. 41 | p(then.Add(diff)) 42 | p(then.Add(-diff)) 43 | } 44 | 45 | // 2012-10-31 15:50:13.793654 +0000 UTC 46 | // 2009-11-17 20:34:58.651387237 +0000 UTC 47 | // 2009 48 | // November 49 | // 17 50 | // 20 51 | // 34 52 | // 58 53 | // 651387237 54 | // UTC 55 | // Tuesday 56 | // true 57 | // false 58 | // false 59 | // 25891h15m15.142266763s 60 | // 25891.25420618521 61 | // 1.5534752523711128e+06 62 | // 9.320851514226677e+07 63 | // 93208515142266763 64 | // 2012-10-31 15:50:13.793654 +0000 UTC 65 | // 2006-12-05 01:19:43.509120474 +0000 UTC 66 | -------------------------------------------------------------------------------- /unix_pipe_channel_note.go: -------------------------------------------------------------------------------- 1 | // 求平方数 2 | // 第一阶段是 gen 函数,它能够将一组整数转换为 channel , 3 | // channel 可以将数字发送出去。 gen 函数首先启动一个 goroutine , 4 | // 该 goroutine 发送数字到 channel ,当数字发送完时关闭 channel 5 | func gen(nums ...int) <-chan int{ 6 | out := make(chan int) 7 | go func () { 8 | for _, n := range nums { 9 | out <-n 10 | } 11 | close(out) //当数字发送完时关闭 channel 12 | }() 13 | return out 14 | } 15 | 16 | // sq 函数,它从 channel 接收一个整数,然后返回 一个 channel ,返回的 channel 17 | // 可以发送 接收到整数的平方。 当它的 inbound channel 关闭,并且把所有数字均发送到下游时,会关闭 outbound channel 18 | 19 | func sq(in <-chan int) <-chan int{ 20 | out := make(chan int) 21 | go func() { 22 | for n:= range in{ 23 | out <- n*n 24 | } 25 | close(out) // 当数字发送完时关闭 channel 26 | }() 27 | return out 28 | } 29 | 30 | //main 函数 用于设置流水线并运行最后一个阶段。最后一个阶段会从第二阶段接收数字,并逐个打印出来, 31 | // 直到来自于上游的 inbound channel 关闭 32 | 33 | func main() { 34 | // 设置流水线 35 | c := gen(2, 3) 36 | out := sq(c) 37 | 38 | // 消费输出结果 39 | fmt.Println(<-out) // 4 40 | fmt.Println(<-out) // 9 41 | } 42 | 43 | // 由于 sq 函数的 inbound channel 和 outbound channel 类型一样, 44 | // 所以组合任意个 sq 函数。比如像下面这样使用: 45 | 46 | func main() { 47 | // 设置流水线并消费输出结果 48 | for n := range sq(sq(gen(2, 3))) { 49 | fmt.Println(n) // 16 then 81 50 | } 51 | } 52 | 53 | 54 | // 扇出:同一个 channel 可以被多个函数读取数据,直到 channel 关闭。 这种机制允许将工作负载分发到一组 worker ,以便更好地并行使用 CPU 和 I/O 。 55 | 56 | // 扇入:多个 channel 的数据可以被同一个函数读取和处理,然后合并到一个 channel ,直到所有 channel 都关闭。 57 | 58 | // 我们修改一下上个例子中的流水线,这里我们运行两个 sq 实例,它们从同一个 channel 读取数据。 这里我们引入一个新函数 merge 对结果进行"扇入"操作 59 | func main() { 60 | in := gen(2,3) 61 | 62 | //启动两个 sq 实例,即两个 goroutines 处理 channel "in" 的数据 63 | c1 := sq(in) 64 | c2 := sq(in) 65 | // merge 函数将 channel c1 和 c2 合并到一起,这段代码会消费 merge 的结果 66 | 67 | for n:= range merge(c1, c2){ 68 | fmt.Println(n) // 打印 4,9 或 9,4 69 | } 70 | } 71 | 72 | // merge 函数 将多个 channel 转换为一个 channel ,它为每一个 inbound channel 启动一个 goroutine , 73 | // 用于将数据 拷贝到 outbound channel 。 merge 函数的实现见下面代码 (注意 wg 变量): 74 | 75 | func merge(cs ...<-chan int) <-chan int { 76 | var wg sync.WaitGroup // 同步锁计数的实现变量 77 | out := make(chan int) 78 | 79 | // 为每一个输入 channel cs 创建一个 goroutine output 80 | // output 将数据从 c 拷贝到 out ,直到 c 关闭,然后 调用 wg.Done 81 | 82 | output := func(c <-chan int){ 83 | for n:= range c { 84 | out <- n 85 | } 86 | wg.Done() 87 | } 88 | wg.Add(len(cs)) 89 | for _, c := range cs { 90 | go output(c) 91 | } 92 | // 启动一个 goroutine ,用于所有 output goroutine 结束时,关闭 out 93 | // 该 goroutine 必须在 wg.Add 之后启动 94 | go func() { 95 | wg.Wait() 96 | close(out) 97 | }() 98 | return out 99 | } 100 | 101 | 102 | // 如果在创建 channel 时就知道要发送的值的个数,使用 buffer 就能够简化代码。 仍然使用求平方数的例子, 103 | // 我们对 gen 函数进行重写。我们将这组整型数拷贝到一个 缓冲 channel 中,从而避免创建一个新的 goroutine 104 | func gen(nums ...int) <-chan int { 105 | out := make(chan int, len(nums)) 106 | for _, n := range nums { 107 | out <- n 108 | } 109 | close(out) 110 | return out 111 | } 112 | 113 | // 回到 流水线中被阻塞的 goroutine ,我们考虑让 merge 函数返回一个缓冲管道: 114 | 115 | func merge(cs ...<-chan int) <-chan int { 116 | var wg sync.WaitGroup 117 | out := make(chan int, 1) // 在本例中存储未读的数据足够了 118 | // ... 其他部分代码不变 ... 119 | 120 | // 尽管这种方法解决了这个程序中阻塞 goroutine 的问题,但是从长远来看,它并不是好办法。 缓存大小选择为 1 是建立在两个前提之上: 121 | // 122 | // 我们已经知道 merge 函数有两个 inbound channel 123 | // 我们已经知道下游阶段会消耗多少个值 124 | // 这段代码很脆弱。如果我们在传入一个值给 gen 函数,或者下游阶段读取的值变少, goroutine 会再次被阻塞。 125 | // 126 | // 为了从根本上解决这个问题,我们需要提供一种机制,让下游阶段能够告知上游发送者停止接收的消息。 下面我们看下这种机制。 127 | 128 | 129 | // 显式取消 (Explicit cancellation) 130 | // 131 | // 当 main 函数决定退出,并停止接收 out 发送的任何数据时,它必须告诉上游阶段的 goroutine 让它们放弃 正在发送的数据。 132 | // main 函数通过发送数据到一个名为 done 的 channel 实现这样的机制。 由于有两个潜在的 发送者被阻塞,它发送两个值 133 | 134 | func main() { 135 | in := gen(2,3) 136 | 137 | // 启动两个运行 sq 的 goroutine 138 | // 两个 goroutine 的数据均来自于 in 139 | 140 | c1 := sq(in) 141 | c2 := sq(in) 142 | 143 | // 消耗 output 生产的第一个值 144 | done := make(chan struct{}, 2) 145 | out := merge(done, c1, c2) 146 | fmt.Println(<-out) // 4 or 9 147 | 148 | // 告诉其他发送者,我们将要离开 149 | // 不再接收它们的数据 150 | done <- struct{}{} 151 | done <- struct{}{} 152 | } 153 | 154 | func merge(done <-chan struct{}, cs ...<-chan int) <-chan int { 155 | var wg sync.WaitGroup 156 | out := make(chan int) 157 | 158 | // 为 cs 的的每一个 输入 channel 159 | // 创建一个 goroutine 。 output 函数将 160 | // 数据从 c 拷贝到 out ,直到 c 关闭, 161 | // 或者接收到 done 信号; 162 | // 然后调用 wg.Done() 163 | output := func(c <-chan int){ 164 | for n := range c { 165 | select{ 166 | case out <-n: 167 | case <-done: 168 | } 169 | wg.Done() 170 | } 171 | // the rest is unchanged 172 | } 173 | 174 | } 175 | 176 | // 我们只要关闭 done channel ,就能够让解开对所有发送者的阻塞。 177 | // 对一个channel的关闭操作事实上是对所有接收者的广播信号 178 | 179 | // 我们把 done channel 作为一个参数传递给每一个 流水线上的函数,通过 defer 表达式声明对 done channel 的关闭操作。 180 | // 因此,所有从 main 函数作为源头被调用的函数均能够收到 done 的信号,每个阶段都能够正常退出。 使用 done 对 main 函数重构以后 181 | 182 | func main() { 183 | // 设置一个 全局共享的 done channel , 184 | // 当流水线退出时,关闭 done channel 185 | // 所有 goroutine 接收到 done 的信号后, 186 | // 都会正常退出。 187 | done := make(chan struct{}) 188 | defer close(done) 189 | 190 | in := gen(done, 2, 3) 191 | 192 | // 将 sq 的工作分发给两个 goroutine 193 | // 这两个 goroutine 均从 in 读取数据 194 | c1 := sq(done, in) 195 | c2 := sq(done, in) 196 | 197 | // 消费 outtput 生产的第一个值 198 | out := merge(done, c1, c2) 199 | fmt.Println(<-out) // 4 or 9 200 | 201 | // defer 调用时, done channel 会被关闭。 202 | } 203 | 204 | // 现在,流水线中的每个阶段都能够在 done channel 被关闭时返回。 merge 函数中的 output 代码也能够顺利返回,因为它 知道 done channel 关闭时, 205 | // 上游发送者 sq 会停止发送数据。 在 defer 表达式执行结束时,所有调用链上的 output 都能保证 wg.Done() 被调用 206 | 207 | func merge(done <-chan struct{}, cs ...<-chan int) <-chan int { 208 | var wg sync.WaitGroup 209 | out := make(chan int) 210 | 211 | // 为 cs 的每一个 channel 创建一个 goroutine 212 | // 这个 goroutine 运行 output ,它将数据从 c 213 | // 拷贝到 out ,直到 c 关闭,或者 接收到 done 214 | // 的关闭信号。人啊后调用 wg.Done() 215 | output := func(c <-chan int) { 216 | defer wg.Done() 217 | for n := range c { 218 | select { 219 | case out <- n: 220 | case <-done: 221 | return 222 | } 223 | } 224 | } 225 | // ... the rest is unchanged ... 226 | } 227 | 228 | 同样的原理, done channel 被关闭时, sq 也能够立即返回。在 defer 表达式执行结束时,所有调用链上的 sq 都能保证 out channel 被关闭 229 | 230 | 231 | func sq(done <-chan struct{}, in <-chan int) <-chan int { 232 | out := make(chan int) 233 | go func() { 234 | defer close(out) 235 | for n := range in { 236 | select { 237 | case out <- n * n: 238 | case <-done: 239 | return 240 | } 241 | } 242 | }() 243 | return out 244 | } 245 | -------------------------------------------------------------------------------- /url-parsing.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "net/url" 7 | ) 8 | 9 | func main() { 10 | s := "postgres://user:pass@host.com:5432/path?k=v#" 11 | 12 | u, err := url.Parse(s) 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | fmt.Println(u.Scheme) 18 | 19 | fmt.Println(u.User) 20 | fmt.Println(u.User.Username()) 21 | p, _ := u.User.Password() 22 | fmt.Println(p) 23 | 24 | // The Host contains both the hostname and the port, if present. Use SplitHostPort to extract them. 25 | fmt.Println(u.Host) 26 | host, port, _ := net.SplitHostPort(u.Host) 27 | fmt.Println(host) 28 | fmt.Println(port) 29 | // Here we extract the path and the fragment after the #. 30 | fmt.Println(u.Path) 31 | fmt.Println(u.Fragment) 32 | // To get query params in a string of k=v format, use RawQuery. You can also parse query params into a map. The parsed query param maps are from strings to slices of strings, so index into [0] if you only want the first value. 33 | fmt.Println(u.RawQuery) 34 | m, _ := url.ParseQuery(u.RawQuery) 35 | fmt.Println(m) 36 | fmt.Println(m["k"][0]) 37 | 38 | u2 := "https://www.google.com" 39 | 40 | i, _ := url.Parse(u2) 41 | 42 | fmt.Println(i) 43 | fmt.Println(i.Scheme) 44 | fmt.Println(i.Host) 45 | } 46 | -------------------------------------------------------------------------------- /variant-types-in-golang.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var x interface{} 8 | 9 | func main() { 10 | x = 5 11 | i, ok := x.(int) 12 | var cells []interface{} = []interface{}{"x", 124, true} 13 | if ok { 14 | fmt.Printf("x holds the integer value %d\n\n", i) 15 | } 16 | 17 | x = "test" 18 | var s = x.(string) 19 | fmt.Printf("The string value of x is now %s\n\n", s) 20 | 21 | x = 5 22 | fmt.Printf("The runtime value of x is now %v\n\n", x) 23 | 24 | for i := 0; i < len(cells); i++ { 25 | fmt.Printf("Item %d ", i) 26 | switch cells[i].(type) { 27 | case int: 28 | fmt.Printf("int : %d\n", cells[i].(int)) 29 | break 30 | case string: 31 | fmt.Printf("string : %s\n", cells[i].(string)) 32 | break 33 | case bool: 34 | fmt.Printf("bool : %t\n", cells[i].(bool)) 35 | break 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /wait-group.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "sync" 5 | 6 | var wg sync.WaitGroup // 1 7 | 8 | func routine(i int) { 9 | defer wg.Done() // 3 10 | fmt.Printf("routine %v finished\n", i) 11 | } 12 | 13 | func main() { 14 | for i := 0; i < 10; i++ { 15 | wg.Add(1) // 2 16 | go routine(i) // * 17 | } 18 | wg.Wait() // 4 19 | fmt.Println("main finished") 20 | } 21 | 22 | // WaitGroup usage in order of execution. 23 | // Declaration of global variable. Making it global is the easiest way to make it visible to all functions and methods. 24 | // Increasing the counter. This must be done in main goroutine because there is no guarantee that newly started goroutine will execute before 4 due to memory model guarantees. 25 | // Decreasing the counter. This must be done at the exit of goroutine. Using deferred call, we make sure that it will be called whenever function ends no matter but no matter how it ends. 26 | // Waiting for the counter to reach 0. This must be done in main goroutine to prevent program exit. 27 | -------------------------------------------------------------------------------- /websocket.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | 9 | "code.google.com/p/go.net/websocket" 10 | ) 11 | 12 | const tpl = ` 13 | 14 | 15 | 43 |

WebSocket Echo Test

44 |
45 |

46 | Message: 47 |

48 |
49 | 50 | 51 | ` 52 | 53 | func Echo(ws *websocket.Conn) { 54 | var err error 55 | 56 | for { 57 | var reply string 58 | 59 | if err = websocket.Message.Receive(ws, &reply); err != nil { 60 | fmt.Println("Can't receive") 61 | break 62 | } 63 | 64 | fmt.Println("Received back from client: " + reply) 65 | 66 | msg := "Received: " + reply 67 | fmt.Println("Sending to client: " + msg) 68 | 69 | if err = websocket.Message.Send(ws, msg); err != nil { 70 | fmt.Println("Can't send") 71 | break 72 | } 73 | } 74 | } 75 | 76 | func myHandler(w http.ResponseWriter, r *http.Request) { 77 | t := template.New("tpl") 78 | content, _ := t.Parse(tpl) 79 | content.Execute(w, nil) 80 | } 81 | 82 | func main() { 83 | http.Handle("/", websocket.Handler(Echo)) 84 | http.Handle("/send", http.HandlerFunc(myHandler)) 85 | 86 | if err := http.ListenAndServe("localhost:1234", nil); err != nil { 87 | log.Fatal("ListenAndServe:", err) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /worker-pools.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func worker(id int, jobs <-chan int, results chan<- int) { 9 | for j := range jobs { 10 | fmt.Println("worker", id, " processing job", j) 11 | time.Sleep(time.Second) 12 | results <- j * 2 13 | } 14 | } 15 | func main() { 16 | jobs := make(chan int, 100) 17 | results := make(chan int, 100) 18 | 19 | // In order to use our pool of workers we need to send them work and collect their results. We make 2 channels for this. 20 | 21 | // This starts up 3 workers, initially blocked because there are no jobs yet. 22 | for w := 1; w <= 3; w++ { 23 | go worker(w, jobs, results) 24 | } 25 | 26 | //Here we send 9 jobs and then close that channel to indicate that’s all the work we have. 27 | for j := 1; j <= 9; j++ { 28 | jobs <- j 29 | } 30 | close(jobs) 31 | 32 | //Finally we collect all the results of the work 33 | for a := 1; a <= 9; a++ { 34 | fmt.Println(<-results) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /writing-files.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | ) 9 | 10 | func check(e error) { 11 | if e != nil { 12 | panic(e) 13 | } 14 | } 15 | 16 | func main() { 17 | d1 := []byte("hello\ngo\n") 18 | // To start, here’s how to dump a string (or just bytes) into a file. 19 | err := ioutil.WriteFile("/tmp/dat1", d1, 0644) 20 | check(err) 21 | 22 | f, err := os.Create("/tmp/dat2") 23 | check(err) 24 | // It’s idiomatic to defer a Close immediately after opening a file. 25 | defer f.Close() 26 | 27 | d2 := []byte{115, 111, 109, 101, 10} 28 | n2, err := f.Write(d2) 29 | check(err) 30 | fmt.Printf("wrote %d bytes\n", n2) 31 | // A WriteString is also available. 32 | n3, err := f.WriteString("hallo\n") 33 | fmt.Printf("wrote %d bytes\n", n3) 34 | f.Sync() 35 | 36 | w := bufio.NewWriter(f) 37 | n4, err := w.WriteString("buffered\n") 38 | fmt.Printf("wrote %d bytes\n", n4) 39 | 40 | // Use Flush to ensure all buffered operations have been applied to the underlying writer. 41 | w.Flush() 42 | } 43 | --------------------------------------------------------------------------------