├── .gitignore ├── README.md ├── bili-stream-example ├── go.mod ├── go.sum └── main.go ├── concurrent-models-example ├── go.mod ├── main.go ├── pool │ └── pool.go └── runner │ └── runner.go ├── context-example ├── client │ └── main.go ├── main.go └── server │ └── main.go ├── gin-example ├── controllers │ └── video-controller.go ├── go.mod ├── go.sum ├── middlewares │ ├── auth.go │ └── logger.go ├── models │ └── video.go └── server.go ├── goroutine-example ├── channel │ └── main.go ├── go.mod ├── main.go └── race_condition │ └── main.go ├── grpc-example ├── go.mod ├── go.sum ├── readme.md ├── route-client │ └── client.go ├── route-server │ └── server.go └── route │ ├── generate.sh │ ├── route.pb.go │ ├── route.proto │ └── route_grpc.pb.go ├── reflection-example ├── 1-interface-values-to-reflection-objects.go ├── 2-reflection-objects-to-interface-values.go ├── 3-setability-modify-reflection-objects.go ├── 4-invoke-methods-from-reflect-obj.go ├── 5-make-func-from-reflect-obj.go └── reflection-examples.go └── testing-example ├── concurrent ├── concurrent.go └── concurrent_test.go └── server ├── go.mod ├── server.go └── server_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 神奇代码在哪里Go语言实战教程 2 | ========================== 3 | 4 | 整活系列:最近在和室友在b站整了一个Golang教学系列。此仓库为视频中所展示的源代码,如有疏漏欢迎提交PR。 5 | 6 | | Topics | Source Code | Video Link | 7 | |------------------------ |------------- |---------------------------------------------- | 8 | | Installations | | https://www.bilibili.com/video/BV18f4y187kT | 9 | | Packages | | https://www.bilibili.com/video/BV1Ff4y187q9 | 10 | | Array/Slice/Map | | https://www.bilibili.com/video/BV1Jo4y1y7yZ | 11 | | Type Systems | | https://www.bilibili.com/video/BV1n54y1G7vy | 12 | | Goroutine | [goroutine-example](./goroutine-example) | https://www.bilibili.com/video/BV1Wy4y1u7cj | 13 | | Concurrent Models | [concurrent-models-example](./concurrent-models-example) | https://www.bilibili.com/video/BV18y4y1u7kP | 14 | | Go Modules | | https://www.bilibili.com/video/BV1w64y197wo | 15 | | Context | [context-example](./context-example) | https://www.bilibili.com/video/BV1rh411a7iz/ | 16 | | Testing & Benchmarking | [testing-example](./testing-example) | https://www.bilibili.com/video/BV1kv411p7Am | 17 | | Reflection | [reflection-example](./reflection-example) | https://www.bilibili.com/video/bv1V5411T7NH | 18 | | Bili Stream Example | [bili-stream-example](./bili-stream-example) | https://www.bilibili.com/video/BV1v64y1t742 | 19 | | gRPC Example | [grpc-example](./grpc-example) | https://www.bilibili.com/video/BV1DV411s7ij | 20 | | etcd中Raft源码赏析 | https://github.com/etcd-io/etcd/tree/main | https://www.bilibili.com/video/BV1Wy4y1K7zF | 21 | | Gin框架 & RESTful APIs | [gin-example](./gin-example) | https://www.bilibili.com/video/BV1Sb4y1r7QZ | 22 | 23 | 24 | -------------------------------------------------------------------------------- /bili-stream-example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/HanFa/learn-go/bili-stream-example 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/JimmyZhangJW/biliStreamClient v0.2.1 7 | github.com/faiface/beep v1.0.2 8 | ) 9 | -------------------------------------------------------------------------------- /bili-stream-example/go.sum: -------------------------------------------------------------------------------- 1 | github.com/JimmyZhangJW/biliStreamClient v0.2.1 h1:AjvSGhHVNFVipfF40dDYxQRjVkGYXYSrKkhsF9j08Lc= 2 | github.com/JimmyZhangJW/biliStreamClient v0.2.1/go.mod h1:AQNlTHiEBUgmub76IctvvK74J3LDwpFyjWJd3m62SU0= 3 | github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ= 4 | github.com/faiface/beep v1.0.2/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM= 5 | github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= 6 | github.com/gdamore/tcell v1.1.1/go.mod h1:K1udHkiR3cOtlpKG5tZPD5XxrF7v2y7lDq7Whcj+xkQ= 7 | github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 8 | github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= 9 | github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 10 | github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m256AsaDPQ+/4= 11 | github.com/gopherjs/gopherwasm v1.0.0 h1:32nge/RlujS1Im4HNCJPp0NbBOAeBXFuT1KonUuLl+Y= 12 | github.com/gopherjs/gopherwasm v1.0.0/go.mod h1:SkZ8z7CWBz5VXbhJel8TxCmAcsQqzgWGR/8nMhyhZSI= 13 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 14 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 15 | github.com/hajimehoshi/go-mp3 v0.1.1/go.mod h1:4i+c5pDNKDrxl1iu9iG90/+fhP37lio6gNhjCx9WBJw= 16 | github.com/hajimehoshi/oto v0.1.1/go.mod h1:hUiLWeBQnbDu4pZsAhOnGqMI1ZGibS6e2qhQdfpwz04= 17 | github.com/hajimehoshi/oto v0.3.1 h1:cpf/uIv4Q0oc5uf9loQn7PIehv+mZerh+0KKma6gzMk= 18 | github.com/hajimehoshi/oto v0.3.1/go.mod h1:e9eTLBB9iZto045HLbzfHJIc+jP3xaKrjZTghvb6fdM= 19 | github.com/jfreymuth/oggvorbis v1.0.0/go.mod h1:abe6F9QRjuU9l+2jek3gj46lu40N4qlYxh2grqkLEDM= 20 | github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= 21 | github.com/lucasb-eyer/go-colorful v0.0.0-20181028223441-12d3b2882a08/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4= 22 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 23 | github.com/mewkiz/flac v1.0.5/go.mod h1:EHZNU32dMF6alpurYyKHDLYpW1lYpBZ5WrXi/VuNIGs= 24 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 25 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 26 | github.com/tencentcloud/tencentcloud-sdk-go v1.0.103 h1:c+eyBAKq8oQFCrr01B3IV3be9SvJmkKpDORVHo49BIY= 27 | github.com/tencentcloud/tencentcloud-sdk-go v1.0.103/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI= 28 | golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd h1:nLIcFw7GiqKXUS7HiChg6OAYWgASB2H97dZKd1GhDSs= 29 | golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 30 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= 31 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 32 | golang.org/x/mobile v0.0.0-20180806140643-507816974b79 h1:t2JRgCWkY7Qaa1J2jal+wqC9OjbyHCHwIA9rVlRUSMo= 33 | golang.org/x/mobile v0.0.0-20180806140643-507816974b79/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 34 | golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30= 35 | golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 37 | gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= 38 | -------------------------------------------------------------------------------- /bili-stream-example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | bili "github.com/JimmyZhangJW/biliStreamClient" 7 | "github.com/faiface/beep/speaker" 8 | "github.com/faiface/beep/wav" 9 | "log" 10 | "time" 11 | ) 12 | 13 | const ( 14 | SecretId = "TODO" 15 | SecretKey = "TODO" 16 | ) 17 | 18 | func main() { 19 | biliClient := bili.New() 20 | biliClient.Connect(4980320) 21 | defer biliClient.Disconnect() 22 | for { 23 | packBody := <-biliClient.Ch 24 | switch packBody.Cmd { 25 | case "DANMU_MSG": 26 | danmu, err := packBody.ParseDanmu() 27 | if err != nil { 28 | log.Fatalln(err) 29 | } 30 | log.Println(danmu) 31 | sanitizedMsg := bili.Sanitize(danmu.Message) 32 | if bili.IsContainChineseWord(sanitizedMsg) { 33 | encodedVoice, err := bili.GetVoiceFromTencentCloud(SecretId, SecretKey, bili.DefaultGirlVoice, danmu.Message) 34 | if err != nil { 35 | log.Fatalln(err) 36 | } 37 | data, err := base64.StdEncoding.DecodeString(encodedVoice) 38 | 39 | streamer, format, err := wav.Decode(bytes.NewReader(data)) 40 | speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) 41 | speaker.Play(streamer) 42 | } 43 | 44 | case "SEND_GIFT": 45 | log.Println(packBody.ParseGift()) 46 | case "COMBO_SEND": 47 | log.Println(packBody.ParseGiftCombo()) 48 | default: 49 | log.Println(packBody.Cmd) 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /concurrent-models-example/go.mod: -------------------------------------------------------------------------------- 1 | module "learn-go-concurrent" 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /concurrent-models-example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "learn-go-concurrent/pool" 7 | "log" 8 | "math/rand" 9 | "sync" 10 | "sync/atomic" 11 | "time" 12 | ) 13 | 14 | // DBConnection 定义的一个资源 15 | type DBConnection struct { 16 | id int32 17 | } 18 | 19 | func (D DBConnection) Close() error { 20 | fmt.Println("database closed , #" + fmt.Sprint(D.id)) 21 | return nil 22 | } 23 | 24 | var counter int32 25 | 26 | func Factory() (io.Closer, error) { 27 | atomic.AddInt32(&counter, 1) 28 | return DBConnection{ 29 | id: counter, 30 | }, nil 31 | } 32 | 33 | func performQuery(query int, pool *pool.Pool) { 34 | defer wg.Done() 35 | 36 | resource, err := pool.AcquireResource() 37 | if err != nil { 38 | log.Fatalln(err) 39 | } 40 | defer pool.ReleaseResource(resource) 41 | 42 | t := rand.Int()%10 + 1 43 | time.Sleep(time.Duration(t) * time.Second) 44 | fmt.Println("finish query" + fmt.Sprint(query)) 45 | 46 | } 47 | 48 | var wg sync.WaitGroup 49 | 50 | func main() { 51 | p, err := pool.New(Factory, 5) 52 | if err != nil { 53 | log.Fatalln(err) 54 | } 55 | 56 | num := 10 57 | wg.Add(num) 58 | for id := 0; id < num; id++ { 59 | go performQuery(id, p) 60 | } 61 | wg.Wait() 62 | 63 | p.Close() 64 | 65 | fmt.Println("pool model run ends") 66 | } 67 | 68 | /* 69 | // runner model demo 70 | func createTask() func(int) { 71 | return func(id int) { 72 | time.Sleep(1 * time.Second) 73 | fmt.Printf("Task complete #%d \n", id) 74 | } 75 | } 76 | 77 | func main() { 78 | 79 | r := runner.New(4 * time.Second) 80 | 81 | r.AddTask(createTask(), createTask(), createTask()) 82 | 83 | err := r.Start() 84 | 85 | switch err { 86 | case runner.ErrInterrupt: 87 | fmt.Println("tasks interrupted") 88 | case runner.ErrTimeout: 89 | fmt.Println("tasks timeout") 90 | default: 91 | fmt.Println("all tasks finished") 92 | } 93 | } 94 | */ 95 | -------------------------------------------------------------------------------- /concurrent-models-example/pool/pool.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "sync" 8 | ) 9 | 10 | var ( 11 | ErrPoolClosed = errors.New("pool has been closed") 12 | ) 13 | 14 | // Pool 资源池,让goroutine们来安全地共享资源 15 | type Pool struct { 16 | factory func() (io.Closer, error) 17 | resources chan io.Closer 18 | 19 | mtx sync.Mutex 20 | closed bool 21 | } 22 | 23 | // New Pool的constructor 24 | func New(factory func() (io.Closer, error), size int) (*Pool, error) { 25 | 26 | if size <= 0 { 27 | return nil, errors.New("invalid size for the resources pool") 28 | } 29 | 30 | return &Pool{ 31 | factory: factory, 32 | resources: make(chan io.Closer, size), 33 | closed: false, 34 | }, nil 35 | } 36 | 37 | func (p *Pool) AcquireResource() (io.Closer, error) { 38 | 39 | select { 40 | case resource, ok := <-p.resources: 41 | if !ok { // p.resources这个chan已经关闭了 42 | return nil, ErrPoolClosed 43 | } 44 | 45 | fmt.Println("acquire resource from the pool") 46 | return resource, nil 47 | default: 48 | fmt.Println("acquire new resource") 49 | return p.factory() // 调用工厂函数 50 | } 51 | } 52 | 53 | func (p *Pool) ReleaseResource(resource io.Closer) { 54 | p.mtx.Lock() 55 | defer p.mtx.Unlock() 56 | 57 | if p.closed { 58 | resource.Close() 59 | return 60 | } 61 | 62 | select { 63 | case p.resources <- resource: // 如果能够丢进去 64 | fmt.Println("release resource back to the pool") 65 | default: 66 | fmt.Println("release resource closed") 67 | resource.Close() 68 | } 69 | } 70 | 71 | func (p *Pool) Close() { 72 | 73 | p.mtx.Lock() 74 | defer p.mtx.Unlock() 75 | 76 | if p.closed{ 77 | return 78 | } 79 | p.closed = true 80 | 81 | close(p.resources) 82 | 83 | for resource :=range p.resources{ 84 | resource.Close() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /concurrent-models-example/runner/runner.go: -------------------------------------------------------------------------------- 1 | package runner 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "os/signal" 7 | "time" 8 | ) 9 | 10 | var ( 11 | ErrTimeout = errors.New("cannot finish tasks within the timeout") 12 | ErrInterrupt = errors.New("received interrupt from OS") 13 | ) 14 | 15 | // Runner 给定一系列的Task,要求在规定的timeout内跑完,不然就报错 16 | // 如果操作系统给了中断信号,也报错 17 | type Runner struct { 18 | interrupt chan os.Signal 19 | complete chan error 20 | 21 | timeout <-chan time.Time // 用来计时 22 | tasks []func(int) // task的列表 23 | } 24 | 25 | func New(t time.Duration) *Runner { 26 | return &Runner{ 27 | interrupt: make(chan os.Signal, 1), 28 | complete: make(chan error), 29 | timeout: time.After(t), 30 | tasks: make([]func(int), 0), 31 | } 32 | } 33 | 34 | func (r *Runner) AddTask(tasks ...func(int)) { 35 | r.tasks = append(r.tasks, tasks...) 36 | } 37 | 38 | func (r *Runner) run() error { 39 | 40 | for id, task := range r.tasks { 41 | select { 42 | case <-r.interrupt: // if there is something in r.interrupt, go here 43 | // 说明操作系统传递了interrupt的信号 44 | signal.Stop(r.interrupt) 45 | return ErrInterrupt 46 | default: // else if r.interrupt is empty, go here 47 | task(id) 48 | } 49 | } 50 | 51 | return nil 52 | } 53 | 54 | func (r *Runner) Start() error { 55 | 56 | // relay interrupt from OS 57 | signal.Notify(r.interrupt, os.Interrupt) 58 | 59 | // run the task 60 | go func() { 61 | r.complete <- r.run() 62 | }() 63 | 64 | select { 65 | case err := <-r.complete: 66 | return err 67 | case <-r.timeout: // 如果执行超时,就会触发到这,返回超时的报错 68 | return ErrTimeout 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /context-example/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net/http" 9 | "time" 10 | ) 11 | 12 | func main() { 13 | 14 | ctx := context.Background() 15 | ctx, cancel := context.WithTimeout(ctx, 3*time.Second) 16 | defer cancel() 17 | 18 | req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | req = req.WithContext(ctx) 23 | 24 | resp, err := http.DefaultClient.Do(req) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | defer resp.Body.Close() 29 | respBytes, err := io.ReadAll(resp.Body) 30 | fmt.Printf("%s", respBytes) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /context-example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | func doSomething(ctx context.Context) { 10 | select { 11 | case <-time.After(5 * time.Second): // 5 seconds pass 12 | fmt.Println("finish doing something") 13 | case <-ctx.Done(): // ctx is cancelled 14 | err := ctx.Err() 15 | if err != nil { 16 | fmt.Println(err.Error()) 17 | } 18 | } 19 | } 20 | 21 | func main() { 22 | // 创建空context的两种方法 23 | ctx := context.Background() // 返回一个空的context,不能被cancel,kv为空 24 | 25 | // todoCtx := context.TODO() // 和Background类似,当你不确定的时候使用 26 | ctx, cancel := context.WithCancel(ctx) 27 | 28 | go func() { 29 | time.Sleep(6 * time.Second) 30 | cancel() 31 | }() 32 | 33 | doSomething(ctx) 34 | 35 | } 36 | -------------------------------------------------------------------------------- /context-example/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | func handler(w http.ResponseWriter, r *http.Request) { 11 | fmt.Println("handler start") 12 | ctx := r.Context() 13 | 14 | complete := make(chan struct{}) 15 | 16 | go func() { 17 | // do something 18 | time.Sleep(5 * time.Second) 19 | complete <- struct{}{} 20 | }() 21 | 22 | select { 23 | case <-complete: // finish doing something 24 | fmt.Println("finish doing something") 25 | case <-ctx.Done(): // ctx is cancelled 26 | err := ctx.Err() 27 | if err != nil { 28 | fmt.Println(err.Error()) 29 | } 30 | } 31 | fmt.Println("handler ends") 32 | } 33 | 34 | func main() { 35 | http.HandleFunc("/", handler) 36 | log.Fatalln(http.ListenAndServe(":8080", nil)) 37 | } 38 | -------------------------------------------------------------------------------- /gin-example/controllers/video-controller.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/HanFa/learn-go/gin-example/models" 5 | "github.com/gin-gonic/gin" 6 | "sync" 7 | ) 8 | 9 | type VideoController interface { 10 | GetAll(context *gin.Context) 11 | 12 | Update(context *gin.Context) 13 | 14 | Create(context *gin.Context) 15 | 16 | Delete(context *gin.Context) 17 | } 18 | 19 | type controller struct { 20 | videos []models.Video 21 | } 22 | 23 | func NewVideoController() VideoController { 24 | return &controller{videos: make([]models.Video, 0)} 25 | } 26 | 27 | type generator struct { 28 | counter int 29 | mtx sync.Mutex 30 | } 31 | 32 | func (g *generator) getNextId() int { 33 | g.mtx.Lock() 34 | defer g.mtx.Unlock() 35 | g.counter++ 36 | return g.counter 37 | } 38 | 39 | var g *generator = &generator{} 40 | 41 | func (c *controller) GetAll(context *gin.Context) { 42 | context.JSON(200, c.videos) 43 | } 44 | 45 | func (c *controller) Update(context *gin.Context) { 46 | var videoToUpdate models.Video 47 | if err := context.ShouldBindUri(&videoToUpdate); err != nil { 48 | context.String(400, "bad request %v", err) 49 | return 50 | } 51 | if err := context.ShouldBind(&videoToUpdate); err != nil { 52 | context.String(400, "bad request %v", err) 53 | return 54 | } 55 | for idx, video := range c.videos { 56 | if video.Id == videoToUpdate.Id { 57 | c.videos[idx] = videoToUpdate 58 | context.String(200, "success, video with id %d has been updated", videoToUpdate.Id) 59 | return 60 | } 61 | } 62 | context.String(400, "bad request cannot find video with %d to update", videoToUpdate.Id) 63 | } 64 | 65 | func (c *controller) Create(context *gin.Context) { 66 | video := models.Video{Id: g.getNextId()} 67 | if err := context.BindJSON(&video); err != nil { 68 | context.String(400, "bad request %v", err) 69 | } 70 | c.videos = append(c.videos, video) 71 | context.String(200, "success, new video id is %d", video.Id) 72 | } 73 | 74 | func (c *controller) Delete(context *gin.Context) { 75 | var videoToDelete models.Video 76 | if err := context.ShouldBindUri(&videoToDelete); err != nil { 77 | context.String(400, "bad request %v", err) 78 | return 79 | } 80 | for idx, video := range c.videos { 81 | if video.Id == videoToDelete.Id { 82 | c.videos = append(c.videos[0:idx], c.videos[idx+1:len(c.videos)]...) 83 | context.String(200, "success, video with id %d has been deleted", videoToDelete.Id) 84 | return 85 | } 86 | } 87 | context.String(400, "bad request cannot find video with %d to delete", videoToDelete.Id) 88 | } 89 | -------------------------------------------------------------------------------- /gin-example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/HanFa/learn-go/gin-example 2 | 3 | go 1.16 4 | 5 | require github.com/gin-gonic/gin v1.7.2 6 | -------------------------------------------------------------------------------- /gin-example/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 5 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 6 | github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= 7 | github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 8 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 9 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 10 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 11 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 12 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 13 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 14 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 15 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 16 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 17 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 18 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 19 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 20 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 21 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 22 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 23 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 24 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 25 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 26 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 27 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= 28 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 29 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 30 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 31 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 32 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 33 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 34 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 35 | github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= 36 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 37 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 38 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 39 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 40 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 41 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 42 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 43 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 44 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 45 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= 46 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 47 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 48 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 49 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 50 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 51 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 52 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 53 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 54 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 55 | -------------------------------------------------------------------------------- /gin-example/middlewares/auth.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import "github.com/gin-gonic/gin" 4 | 5 | func MyAuth() gin.HandlerFunc { 6 | return gin.BasicAuth(gin.Accounts{ 7 | "chong": "password", 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /gin-example/middlewares/logger.go: -------------------------------------------------------------------------------- 1 | package middlewares 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | func MyLogger() gin.HandlerFunc { 9 | return gin.LoggerWithFormatter(func(params gin.LogFormatterParams) string { 10 | return fmt.Sprintf("%s %s %s\n", params.ClientIP, params.Method, params.Path) 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /gin-example/models/video.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type Video struct { 4 | Id int `uri:"id"` 5 | Title string `form:"title"` 6 | Description string `form:"description"` 7 | } 8 | -------------------------------------------------------------------------------- /gin-example/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/HanFa/learn-go/gin-example/controllers" 5 | "github.com/HanFa/learn-go/gin-example/middlewares" 6 | "github.com/gin-gonic/gin" 7 | "log" 8 | ) 9 | 10 | func main() { 11 | 12 | server := gin.Default() 13 | 14 | server.GET("/ping", func(context *gin.Context) { 15 | context.String(200, "%s", "pong") 16 | }) 17 | 18 | server.Static("/resources", "./resources") 19 | server.StaticFile("/mycoolvideo", "./resources/海豹.mp4") 20 | 21 | videoController := controllers.NewVideoController() 22 | videoGroup := server.Group("/videos") 23 | videoGroup.Use(middlewares.MyLogger()) 24 | 25 | // GET /videos 26 | videoGroup.GET("/", videoController.GetAll) 27 | 28 | // PUT /videos/123 29 | videoGroup.PUT("/:id", videoController.Update) 30 | 31 | // POST /videos 32 | videoGroup.POST("/", videoController.Create) 33 | 34 | // DELETE /videos/123 35 | videoGroup.DELETE("/:id", videoController.Delete) 36 | 37 | log.Fatalln(server.Run("localhost:8080")) 38 | } 39 | -------------------------------------------------------------------------------- /goroutine-example/channel/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @project learn-go 3 | * @Author 27 4 | * @Date 2021/7/15 22:46 7月 5 | **/ 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "math/rand" 11 | "sync" 12 | ) 13 | 14 | var wg sync.WaitGroup 15 | 16 | func player(name string, ch chan int) { 17 | defer wg.Done() // 任务完成 18 | for { 19 | ball, ok := <-ch // 怎样从通道拿值 20 | if !ok { // 通道关闭, 说明可以理解为对手没有把球打回来 21 | fmt.Printf("channel is closed %s wins!\n", name) 22 | return 23 | } 24 | 25 | n := rand.Intn(100) 26 | if n%10 == 0 { // 模拟十分之一几率 27 | // 把球打飞,用关闭通道模拟 28 | close(ch) 29 | fmt.Printf("%s misses the ball! %s losses\n", name, name) 30 | return 31 | } 32 | ball++ 33 | fmt.Printf("%s receivces ball %d\n", name, ball) 34 | ch <- ball 35 | } 36 | } 37 | 38 | func main() { 39 | wg.Add(2) 40 | 41 | ch := make(chan int, 0) // unbuffered channel 42 | 43 | go player("heli", ch) 44 | go player("chong", ch) 45 | 46 | ch <- 0 47 | 48 | wg.Wait() 49 | } 50 | -------------------------------------------------------------------------------- /goroutine-example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/HanFa/learn-go/goroutine-example 2 | 3 | go 1.16 4 | -------------------------------------------------------------------------------- /goroutine-example/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @project learn-go 3 | * @Author 27 4 | * @Date 2021/7/15 22:39 7月 5 | **/ 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | var wg sync.WaitGroup 15 | 16 | func say(id string) { 17 | time.Sleep(time.Second) 18 | fmt.Println("I am done!id: " + id) 19 | wg. Done() // 任务完成 20 | } 21 | 22 | 23 | 24 | func main() { 25 | wg.Add(2) // 总共有两个任务 26 | 27 | go func(id string) { 28 | fmt.Println(id) 29 | wg.Done() 30 | }("hello") 31 | 32 | go say("world") 33 | 34 | wg.Wait() // 等待所有任务完成 卡住,如果wg不是0 35 | fmt.Print("exit") 36 | } 37 | 38 | -------------------------------------------------------------------------------- /goroutine-example/race_condition/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @project learn-go 3 | * @Author 27 4 | * @Date 2021/7/15 23:55 7月 5 | **/ 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "sync" 11 | "sync/atomic" 12 | ) 13 | 14 | var wg sync.WaitGroup 15 | var counter int32 16 | var mtx sync.Mutex 17 | var ch = make(chan int, 1) 18 | /* 19 | 这里改为 bufferd 原因是最后一个循环把数送进ch后没有再一个循环从ch拿值 20 | 加上bufferd 最后ch存有一个值, 这样可以结束goroutine 外面从里面拿出那个结果 21 | */ 22 | 23 | // ================================== 竞争条件情况 24 | func UnsafeIncCounter() { 25 | defer wg.Done() 26 | for i := 0; i < 10000; i ++ { 27 | //counter ++ 28 | // 以上实际上是以下逻辑步骤 29 | temp := counter // 读 30 | temp = temp + 1 // 计算 31 | counter = temp // 写入 32 | } 33 | } 34 | 35 | func raceConditionDemo() { 36 | wg.Add(2) 37 | 38 | go UnsafeIncCounter() 39 | go UnsafeIncCounter() 40 | 41 | wg.Wait() 42 | 43 | fmt.Println(counter) 44 | } 45 | 46 | // ================================== 正常且安全情况 47 | func MutexIncCounter() { 48 | defer wg.Done() 49 | for i := 0; i < 10000; i ++ { 50 | // race condition here 竞争条件 51 | mtx.Lock() 52 | counter ++ // 共享资源 53 | mtx.Unlock() 54 | } 55 | } 56 | 57 | func AtomicIncCounter() { 58 | defer wg.Done() 59 | for i := 0; i < 10000; i ++ { 60 | // race condition here 竞争条件 61 | atomic.AddInt32(&counter, 1) 62 | } 63 | } 64 | 65 | func mutexDemo() { 66 | wg.Add(2) 67 | 68 | go MutexIncCounter() 69 | go MutexIncCounter() 70 | 71 | wg.Wait() 72 | 73 | fmt.Println(counter) 74 | } 75 | 76 | func atomicDemo() { 77 | wg.Add(2) 78 | 79 | go AtomicIncCounter() 80 | go AtomicIncCounter() 81 | 82 | wg.Wait() 83 | 84 | fmt.Println(counter) 85 | } 86 | 87 | func ChannelIncCounter() { 88 | defer wg.Done() 89 | for i := 0; i < 10000; i ++ { 90 | count := <- ch 91 | count ++ 92 | fmt.Println(count) 93 | ch <- count 94 | } 95 | } 96 | 97 | func channelDemo() { 98 | wg.Add(2) 99 | 100 | // race condition 101 | go ChannelIncCounter() 102 | go ChannelIncCounter() 103 | 104 | ch <- 0 105 | 106 | wg.Wait() 107 | 108 | fmt.Println(<- ch) 109 | } 110 | 111 | 112 | func main() { 113 | // 运行以下是race condition 情况 114 | //raceConditionDemo() 115 | 116 | // 以下是正常情况 117 | //mutexDemo() 118 | 119 | //atomicDemo() 120 | 121 | channelDemo() 122 | } 123 | -------------------------------------------------------------------------------- /grpc-example/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/HanFa/learn-go/grpc-example 2 | 3 | go 1.16 4 | 5 | require ( 6 | google.golang.org/grpc v1.38.0 7 | google.golang.org/protobuf v1.26.0 8 | ) 9 | -------------------------------------------------------------------------------- /grpc-example/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 4 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 5 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 8 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 9 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 10 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 11 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 12 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 13 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 14 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 15 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 16 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 17 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 18 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 19 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 20 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 21 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 22 | github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= 23 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 24 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 25 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 26 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 27 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 28 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 29 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 30 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 31 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 32 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 33 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 34 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 35 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 36 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 37 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 38 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 39 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 40 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 41 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 42 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 43 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 44 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 45 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 46 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 47 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 48 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 49 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 50 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 51 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 52 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 53 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 54 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 55 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 56 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 57 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 58 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 59 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 60 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 61 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 62 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 63 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 64 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 65 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 66 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 67 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 68 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 69 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 70 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 71 | google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= 72 | google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= 73 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 74 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 75 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 76 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 77 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 78 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 79 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 80 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 81 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 82 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 83 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 84 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 85 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 86 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 87 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 88 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 89 | -------------------------------------------------------------------------------- /grpc-example/readme.md: -------------------------------------------------------------------------------- 1 | Adapted from the official gRPC-go example. 2 | 3 | https://github.com/grpc/grpc-go/tree/master/examples/route_guide 4 | -------------------------------------------------------------------------------- /grpc-example/route-client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "fmt" 7 | "io" 8 | "log" 9 | "os" 10 | "time" 11 | 12 | pb "github.com/HanFa/learn-go/grpc-example/route" 13 | "google.golang.org/grpc" 14 | ) 15 | 16 | func runFirst(client pb.RouteGuideClient) { 17 | feature, err := client.GetFeature(context.Background(), &pb.Point{ 18 | Latitude: 310235000, 19 | Longitude: 121437403, 20 | }) 21 | if err != nil { 22 | log.Fatalln(err) 23 | } 24 | fmt.Println(feature) 25 | } 26 | 27 | func runSecond(client pb.RouteGuideClient) { 28 | serverStream, err := client.ListFeatures(context.Background(), &pb.Rectangle{ 29 | Lo: &pb.Point{Latitude: 313374060, Longitude: 121358540}, 30 | Hi: &pb.Point{Latitude: 311034130, Longitude: 121598790}, 31 | }) 32 | if err != nil { 33 | log.Fatalln(err) 34 | } 35 | 36 | for { 37 | feature, err := serverStream.Recv() 38 | if err == io.EOF { 39 | break 40 | } 41 | if err != nil { 42 | log.Fatalln(err) 43 | } 44 | fmt.Println(feature) 45 | } 46 | } 47 | 48 | func runThird(client pb.RouteGuideClient) { 49 | // dummy data 50 | points := []*pb.Point{ 51 | {Latitude: 313374060, Longitude: 121358540}, 52 | {Latitude: 311034130, Longitude: 121598790}, 53 | {Latitude: 310235000, Longitude: 121437403}, 54 | } 55 | 56 | clientStream, err := client.RecordRoute(context.Background()) 57 | if err != nil { 58 | log.Fatalln(err) 59 | } 60 | 61 | for _, point := range points { 62 | if err := clientStream.Send(point); err != nil { 63 | log.Fatalln(err) 64 | } 65 | time.Sleep(time.Second) 66 | } 67 | summary, err := clientStream.CloseAndRecv() 68 | if err != nil { 69 | log.Fatalln(err) 70 | } 71 | fmt.Println(summary) 72 | } 73 | 74 | func readIntFromCommandLine(reader *bufio.Reader, target *int32) { 75 | _, err := fmt.Fscanf(reader, "%d\n", target) 76 | if err != nil { 77 | log.Fatalln("Cannot scan", err) 78 | } 79 | } 80 | 81 | func runForth(client pb.RouteGuideClient) { 82 | stream, err := client.Recommend(context.Background()) 83 | if err != nil { 84 | log.Fatalln(err) 85 | } 86 | 87 | // this goroutine listen to the server stream 88 | go func() { 89 | for { 90 | feature, err2 := stream.Recv() 91 | if err2 == io.EOF { 92 | break 93 | } 94 | if err2 != nil { 95 | log.Fatalln(err2) 96 | } 97 | fmt.Println("Recommended: ", feature) 98 | } 99 | }() 100 | 101 | reader := bufio.NewReader(os.Stdin) 102 | 103 | for { 104 | request := pb.RecommendationRequest{Point: new(pb.Point)} 105 | var mode int32 106 | fmt.Print("Enter Recommendation Mode (0 for farthest, 1 for the nearest)") 107 | readIntFromCommandLine(reader, &mode) 108 | fmt.Print("Enter Latitude: ") 109 | readIntFromCommandLine(reader, &request.Point.Latitude) 110 | fmt.Print("Enter Longitude: ") 111 | readIntFromCommandLine(reader, &request.Point.Longitude) 112 | request.Mode = pb.RecommendationMode(mode) 113 | 114 | if err := stream.Send(&request); err != nil { 115 | log.Fatalln(err) 116 | } 117 | time.Sleep(100 * time.Millisecond) 118 | } 119 | } 120 | 121 | func main() { 122 | 123 | conn, err := grpc.Dial("localhost:5000", grpc.WithInsecure(), grpc.WithBlock()) 124 | if err != nil { 125 | log.Fatalln("client cannot dial grpc server") 126 | } 127 | defer conn.Close() 128 | 129 | client := pb.NewRouteGuideClient(conn) 130 | 131 | runForth(client) 132 | } 133 | -------------------------------------------------------------------------------- /grpc-example/route-server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "google.golang.org/protobuf/proto" 6 | "io" 7 | "log" 8 | "math" 9 | "net" 10 | "time" 11 | 12 | pb "github.com/HanFa/learn-go/grpc-example/route" 13 | "google.golang.org/grpc" 14 | ) 15 | 16 | type routeGuideServer struct { 17 | features []*pb.Feature 18 | pb.UnimplementedRouteGuideServer 19 | } 20 | 21 | func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) { 22 | for _, feature := range s.features { 23 | if proto.Equal(feature.Location, point) { 24 | return feature, nil 25 | } 26 | } 27 | return nil, nil 28 | } 29 | 30 | // check if a point is inside a rectangle 31 | func inRange(point *pb.Point, rect *pb.Rectangle) bool { 32 | left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude)) 33 | right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude)) 34 | top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude)) 35 | bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude)) 36 | 37 | if float64(point.Longitude) >= left && 38 | float64(point.Longitude) <= right && 39 | float64(point.Latitude) >= bottom && 40 | float64(point.Latitude) <= top { 41 | return true 42 | } 43 | return false 44 | } 45 | 46 | func (s *routeGuideServer) ListFeatures(rectangle *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error { 47 | for _, feature := range s.features { 48 | if inRange(feature.Location, rectangle) { 49 | if err := stream.Send(feature); err != nil { 50 | return err 51 | } 52 | } 53 | } 54 | return nil 55 | } 56 | 57 | func toRadians(num float64) float64 { 58 | return num * math.Pi / float64(180) 59 | } 60 | 61 | // calcDistance calculates the distance between two points using the "haversine" formula. 62 | // The formula is based on http://mathforum.org/library/drmath/view/51879.html. 63 | func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 { 64 | const CordFactor float64 = 1e7 65 | const R = float64(6371000) // earth radius in metres 66 | lat1 := toRadians(float64(p1.Latitude) / CordFactor) 67 | lat2 := toRadians(float64(p2.Latitude) / CordFactor) 68 | lng1 := toRadians(float64(p1.Longitude) / CordFactor) 69 | lng2 := toRadians(float64(p2.Longitude) / CordFactor) 70 | dlat := lat2 - lat1 71 | dlng := lng2 - lng1 72 | 73 | a := math.Sin(dlat/2)*math.Sin(dlat/2) + 74 | math.Cos(lat1)*math.Cos(lat2)* 75 | math.Sin(dlng/2)*math.Sin(dlng/2) 76 | c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a)) 77 | 78 | distance := R * c 79 | return int32(distance) 80 | } 81 | 82 | func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error { 83 | startTime := time.Now() 84 | var pointCount, distance int32 85 | var prevPoint *pb.Point 86 | for { 87 | point, err := stream.Recv() 88 | if err == io.EOF { 89 | // conclude a route summary 90 | endTime := time.Now() 91 | return stream.SendAndClose(&pb.RouteSummary{ 92 | PointCount: pointCount, 93 | Distance: distance, 94 | ElapsedTime: int32(endTime.Sub(startTime).Seconds()), 95 | }) 96 | } 97 | if err != nil { 98 | return err 99 | } 100 | 101 | pointCount++ 102 | if prevPoint != nil { 103 | distance += calcDistance(prevPoint, point) 104 | } 105 | prevPoint = point 106 | } 107 | 108 | return nil 109 | } 110 | 111 | func (s *routeGuideServer) recommendOnce(request *pb.RecommendationRequest) (*pb.Feature, error) { 112 | var nearest, farthest *pb.Feature 113 | var nearestDistance, farthestDistance int32 114 | 115 | for _, feature := range s.features { 116 | distance := calcDistance(feature.Location, request.Point) 117 | if nearest == nil || distance < nearestDistance { 118 | nearestDistance = distance 119 | nearest = feature 120 | } 121 | if farthest == nil || distance > farthestDistance { 122 | farthestDistance = distance 123 | farthest = feature 124 | } 125 | } 126 | if request.Mode == pb.RecommendationMode_GetFarthest { 127 | return farthest, nil 128 | } else { 129 | return nearest, nil 130 | } 131 | } 132 | 133 | func (s *routeGuideServer) Recommend(stream pb.RouteGuide_RecommendServer) error { 134 | for { 135 | request, err := stream.Recv() 136 | if err == io.EOF { 137 | return nil 138 | } 139 | if err != nil { 140 | return err 141 | } 142 | recommended, err := s.recommendOnce(request) 143 | if err != nil { 144 | return err 145 | } 146 | err = stream.Send(recommended) 147 | if err != nil { 148 | return err 149 | } 150 | } 151 | } 152 | 153 | func newServer() *routeGuideServer { 154 | return &routeGuideServer{ 155 | features: []*pb.Feature{ 156 | {Name: "上海交通大学闵行校区 上海市闵行区东川路800号", Location: &pb.Point{ 157 | Latitude: 310235000, 158 | Longitude: 121437403, 159 | }}, 160 | {Name: "复旦大学 上海市杨浦区五角场邯郸路220号", Location: &pb.Point{ 161 | Latitude: 312978870, 162 | Longitude: 121503457, 163 | }}, 164 | {Name: "华东理工大学 上海市徐汇区梅陇路130号", Location: &pb.Point{ 165 | Latitude: 311416130, 166 | Longitude: 121424904, 167 | }}, 168 | }, 169 | } 170 | } 171 | 172 | func main() { 173 | 174 | lis, err := net.Listen("tcp", "localhost:5000") 175 | if err != nil { 176 | log.Fatalln("cannot create a listener at the address") 177 | } 178 | grpcServer := grpc.NewServer() 179 | pb.RegisterRouteGuideServer(grpcServer, newServer()) 180 | log.Fatalln(grpcServer.Serve(lis)) 181 | } 182 | -------------------------------------------------------------------------------- /grpc-example/route/generate.sh: -------------------------------------------------------------------------------- 1 | protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative route.proto -------------------------------------------------------------------------------- /grpc-example/route/route.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.26.0 4 | // protoc v3.15.3 5 | // source: route.proto 6 | 7 | package route 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | type RecommendationMode int32 24 | 25 | const ( 26 | RecommendationMode_GetFarthest RecommendationMode = 0 27 | RecommendationMode_GetNearest RecommendationMode = 1 28 | ) 29 | 30 | // Enum value maps for RecommendationMode. 31 | var ( 32 | RecommendationMode_name = map[int32]string{ 33 | 0: "GetFarthest", 34 | 1: "GetNearest", 35 | } 36 | RecommendationMode_value = map[string]int32{ 37 | "GetFarthest": 0, 38 | "GetNearest": 1, 39 | } 40 | ) 41 | 42 | func (x RecommendationMode) Enum() *RecommendationMode { 43 | p := new(RecommendationMode) 44 | *p = x 45 | return p 46 | } 47 | 48 | func (x RecommendationMode) String() string { 49 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 50 | } 51 | 52 | func (RecommendationMode) Descriptor() protoreflect.EnumDescriptor { 53 | return file_route_proto_enumTypes[0].Descriptor() 54 | } 55 | 56 | func (RecommendationMode) Type() protoreflect.EnumType { 57 | return &file_route_proto_enumTypes[0] 58 | } 59 | 60 | func (x RecommendationMode) Number() protoreflect.EnumNumber { 61 | return protoreflect.EnumNumber(x) 62 | } 63 | 64 | // Deprecated: Use RecommendationMode.Descriptor instead. 65 | func (RecommendationMode) EnumDescriptor() ([]byte, []int) { 66 | return file_route_proto_rawDescGZIP(), []int{0} 67 | } 68 | 69 | type Point struct { 70 | state protoimpl.MessageState 71 | sizeCache protoimpl.SizeCache 72 | unknownFields protoimpl.UnknownFields 73 | 74 | Latitude int32 `protobuf:"varint,1,opt,name=latitude,proto3" json:"latitude,omitempty"` 75 | Longitude int32 `protobuf:"varint,2,opt,name=longitude,proto3" json:"longitude,omitempty"` 76 | } 77 | 78 | func (x *Point) Reset() { 79 | *x = Point{} 80 | if protoimpl.UnsafeEnabled { 81 | mi := &file_route_proto_msgTypes[0] 82 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 83 | ms.StoreMessageInfo(mi) 84 | } 85 | } 86 | 87 | func (x *Point) String() string { 88 | return protoimpl.X.MessageStringOf(x) 89 | } 90 | 91 | func (*Point) ProtoMessage() {} 92 | 93 | func (x *Point) ProtoReflect() protoreflect.Message { 94 | mi := &file_route_proto_msgTypes[0] 95 | if protoimpl.UnsafeEnabled && x != nil { 96 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 97 | if ms.LoadMessageInfo() == nil { 98 | ms.StoreMessageInfo(mi) 99 | } 100 | return ms 101 | } 102 | return mi.MessageOf(x) 103 | } 104 | 105 | // Deprecated: Use Point.ProtoReflect.Descriptor instead. 106 | func (*Point) Descriptor() ([]byte, []int) { 107 | return file_route_proto_rawDescGZIP(), []int{0} 108 | } 109 | 110 | func (x *Point) GetLatitude() int32 { 111 | if x != nil { 112 | return x.Latitude 113 | } 114 | return 0 115 | } 116 | 117 | func (x *Point) GetLongitude() int32 { 118 | if x != nil { 119 | return x.Longitude 120 | } 121 | return 0 122 | } 123 | 124 | type Rectangle struct { 125 | state protoimpl.MessageState 126 | sizeCache protoimpl.SizeCache 127 | unknownFields protoimpl.UnknownFields 128 | 129 | Lo *Point `protobuf:"bytes,1,opt,name=lo,proto3" json:"lo,omitempty"` 130 | Hi *Point `protobuf:"bytes,2,opt,name=hi,proto3" json:"hi,omitempty"` 131 | } 132 | 133 | func (x *Rectangle) Reset() { 134 | *x = Rectangle{} 135 | if protoimpl.UnsafeEnabled { 136 | mi := &file_route_proto_msgTypes[1] 137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 138 | ms.StoreMessageInfo(mi) 139 | } 140 | } 141 | 142 | func (x *Rectangle) String() string { 143 | return protoimpl.X.MessageStringOf(x) 144 | } 145 | 146 | func (*Rectangle) ProtoMessage() {} 147 | 148 | func (x *Rectangle) ProtoReflect() protoreflect.Message { 149 | mi := &file_route_proto_msgTypes[1] 150 | if protoimpl.UnsafeEnabled && x != nil { 151 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 152 | if ms.LoadMessageInfo() == nil { 153 | ms.StoreMessageInfo(mi) 154 | } 155 | return ms 156 | } 157 | return mi.MessageOf(x) 158 | } 159 | 160 | // Deprecated: Use Rectangle.ProtoReflect.Descriptor instead. 161 | func (*Rectangle) Descriptor() ([]byte, []int) { 162 | return file_route_proto_rawDescGZIP(), []int{1} 163 | } 164 | 165 | func (x *Rectangle) GetLo() *Point { 166 | if x != nil { 167 | return x.Lo 168 | } 169 | return nil 170 | } 171 | 172 | func (x *Rectangle) GetHi() *Point { 173 | if x != nil { 174 | return x.Hi 175 | } 176 | return nil 177 | } 178 | 179 | type Feature struct { 180 | state protoimpl.MessageState 181 | sizeCache protoimpl.SizeCache 182 | unknownFields protoimpl.UnknownFields 183 | 184 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 185 | Location *Point `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` 186 | } 187 | 188 | func (x *Feature) Reset() { 189 | *x = Feature{} 190 | if protoimpl.UnsafeEnabled { 191 | mi := &file_route_proto_msgTypes[2] 192 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 193 | ms.StoreMessageInfo(mi) 194 | } 195 | } 196 | 197 | func (x *Feature) String() string { 198 | return protoimpl.X.MessageStringOf(x) 199 | } 200 | 201 | func (*Feature) ProtoMessage() {} 202 | 203 | func (x *Feature) ProtoReflect() protoreflect.Message { 204 | mi := &file_route_proto_msgTypes[2] 205 | if protoimpl.UnsafeEnabled && x != nil { 206 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 207 | if ms.LoadMessageInfo() == nil { 208 | ms.StoreMessageInfo(mi) 209 | } 210 | return ms 211 | } 212 | return mi.MessageOf(x) 213 | } 214 | 215 | // Deprecated: Use Feature.ProtoReflect.Descriptor instead. 216 | func (*Feature) Descriptor() ([]byte, []int) { 217 | return file_route_proto_rawDescGZIP(), []int{2} 218 | } 219 | 220 | func (x *Feature) GetName() string { 221 | if x != nil { 222 | return x.Name 223 | } 224 | return "" 225 | } 226 | 227 | func (x *Feature) GetLocation() *Point { 228 | if x != nil { 229 | return x.Location 230 | } 231 | return nil 232 | } 233 | 234 | type RouteSummary struct { 235 | state protoimpl.MessageState 236 | sizeCache protoimpl.SizeCache 237 | unknownFields protoimpl.UnknownFields 238 | 239 | PointCount int32 `protobuf:"varint,1,opt,name=point_count,json=pointCount,proto3" json:"point_count,omitempty"` 240 | Distance int32 `protobuf:"varint,2,opt,name=distance,proto3" json:"distance,omitempty"` 241 | ElapsedTime int32 `protobuf:"varint,3,opt,name=elapsed_time,json=elapsedTime,proto3" json:"elapsed_time,omitempty"` 242 | } 243 | 244 | func (x *RouteSummary) Reset() { 245 | *x = RouteSummary{} 246 | if protoimpl.UnsafeEnabled { 247 | mi := &file_route_proto_msgTypes[3] 248 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 249 | ms.StoreMessageInfo(mi) 250 | } 251 | } 252 | 253 | func (x *RouteSummary) String() string { 254 | return protoimpl.X.MessageStringOf(x) 255 | } 256 | 257 | func (*RouteSummary) ProtoMessage() {} 258 | 259 | func (x *RouteSummary) ProtoReflect() protoreflect.Message { 260 | mi := &file_route_proto_msgTypes[3] 261 | if protoimpl.UnsafeEnabled && x != nil { 262 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 263 | if ms.LoadMessageInfo() == nil { 264 | ms.StoreMessageInfo(mi) 265 | } 266 | return ms 267 | } 268 | return mi.MessageOf(x) 269 | } 270 | 271 | // Deprecated: Use RouteSummary.ProtoReflect.Descriptor instead. 272 | func (*RouteSummary) Descriptor() ([]byte, []int) { 273 | return file_route_proto_rawDescGZIP(), []int{3} 274 | } 275 | 276 | func (x *RouteSummary) GetPointCount() int32 { 277 | if x != nil { 278 | return x.PointCount 279 | } 280 | return 0 281 | } 282 | 283 | func (x *RouteSummary) GetDistance() int32 { 284 | if x != nil { 285 | return x.Distance 286 | } 287 | return 0 288 | } 289 | 290 | func (x *RouteSummary) GetElapsedTime() int32 { 291 | if x != nil { 292 | return x.ElapsedTime 293 | } 294 | return 0 295 | } 296 | 297 | type RecommendationRequest struct { 298 | state protoimpl.MessageState 299 | sizeCache protoimpl.SizeCache 300 | unknownFields protoimpl.UnknownFields 301 | 302 | Mode RecommendationMode `protobuf:"varint,1,opt,name=mode,proto3,enum=route.RecommendationMode" json:"mode,omitempty"` 303 | Point *Point `protobuf:"bytes,2,opt,name=point,proto3" json:"point,omitempty"` 304 | } 305 | 306 | func (x *RecommendationRequest) Reset() { 307 | *x = RecommendationRequest{} 308 | if protoimpl.UnsafeEnabled { 309 | mi := &file_route_proto_msgTypes[4] 310 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 311 | ms.StoreMessageInfo(mi) 312 | } 313 | } 314 | 315 | func (x *RecommendationRequest) String() string { 316 | return protoimpl.X.MessageStringOf(x) 317 | } 318 | 319 | func (*RecommendationRequest) ProtoMessage() {} 320 | 321 | func (x *RecommendationRequest) ProtoReflect() protoreflect.Message { 322 | mi := &file_route_proto_msgTypes[4] 323 | if protoimpl.UnsafeEnabled && x != nil { 324 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 325 | if ms.LoadMessageInfo() == nil { 326 | ms.StoreMessageInfo(mi) 327 | } 328 | return ms 329 | } 330 | return mi.MessageOf(x) 331 | } 332 | 333 | // Deprecated: Use RecommendationRequest.ProtoReflect.Descriptor instead. 334 | func (*RecommendationRequest) Descriptor() ([]byte, []int) { 335 | return file_route_proto_rawDescGZIP(), []int{4} 336 | } 337 | 338 | func (x *RecommendationRequest) GetMode() RecommendationMode { 339 | if x != nil { 340 | return x.Mode 341 | } 342 | return RecommendationMode_GetFarthest 343 | } 344 | 345 | func (x *RecommendationRequest) GetPoint() *Point { 346 | if x != nil { 347 | return x.Point 348 | } 349 | return nil 350 | } 351 | 352 | var File_route_proto protoreflect.FileDescriptor 353 | 354 | var file_route_proto_rawDesc = []byte{ 355 | 0x0a, 0x0b, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x72, 356 | 0x6f, 0x75, 0x74, 0x65, 0x22, 0x41, 0x0a, 0x05, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 357 | 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 358 | 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 359 | 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6c, 0x6f, 360 | 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x47, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x74, 0x61, 361 | 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x02, 0x6c, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 362 | 0x32, 0x0c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x02, 363 | 0x6c, 0x6f, 0x12, 0x1c, 0x0a, 0x02, 0x68, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 364 | 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x02, 0x68, 0x69, 365 | 0x22, 0x47, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 366 | 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 367 | 0x28, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 368 | 0x0b, 0x32, 0x0c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 369 | 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6e, 0x0a, 0x0c, 0x52, 0x6f, 0x75, 370 | 0x74, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, 0x69, 371 | 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 372 | 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 373 | 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x69, 374 | 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 375 | 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x6c, 376 | 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x6a, 0x0a, 0x15, 0x52, 0x65, 0x63, 377 | 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 378 | 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 379 | 0x32, 0x19, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 380 | 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 381 | 0x65, 0x12, 0x22, 0x0a, 0x05, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 382 | 0x32, 0x0c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x05, 383 | 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2a, 0x35, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 384 | 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x47, 385 | 0x65, 0x74, 0x46, 0x61, 0x72, 0x74, 0x68, 0x65, 0x73, 0x74, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 386 | 0x47, 0x65, 0x74, 0x4e, 0x65, 0x61, 0x72, 0x65, 0x73, 0x74, 0x10, 0x01, 0x32, 0xe7, 0x01, 0x0a, 387 | 0x0a, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x47, 0x75, 0x69, 0x64, 0x65, 0x12, 0x2c, 0x0a, 0x0a, 0x47, 388 | 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x0c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 389 | 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x0e, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 390 | 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x00, 0x12, 0x34, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 391 | 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x2e, 0x72, 0x6f, 0x75, 0x74, 392 | 0x65, 0x2e, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x1a, 0x0e, 0x2e, 0x72, 0x6f, 393 | 0x75, 0x74, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 394 | 0x34, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0c, 395 | 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x13, 0x2e, 0x72, 396 | 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 397 | 0x79, 0x22, 0x00, 0x28, 0x01, 0x12, 0x3f, 0x0a, 0x09, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 398 | 0x6e, 0x64, 0x12, 0x1c, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6d, 399 | 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 400 | 0x1a, 0x0e, 0x2e, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 401 | 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 402 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x48, 0x61, 0x6e, 0x46, 0x61, 0x2f, 0x6c, 0x65, 0x61, 0x72, 0x6e, 403 | 0x2d, 0x67, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 404 | 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 405 | } 406 | 407 | var ( 408 | file_route_proto_rawDescOnce sync.Once 409 | file_route_proto_rawDescData = file_route_proto_rawDesc 410 | ) 411 | 412 | func file_route_proto_rawDescGZIP() []byte { 413 | file_route_proto_rawDescOnce.Do(func() { 414 | file_route_proto_rawDescData = protoimpl.X.CompressGZIP(file_route_proto_rawDescData) 415 | }) 416 | return file_route_proto_rawDescData 417 | } 418 | 419 | var file_route_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 420 | var file_route_proto_msgTypes = make([]protoimpl.MessageInfo, 5) 421 | var file_route_proto_goTypes = []interface{}{ 422 | (RecommendationMode)(0), // 0: route.RecommendationMode 423 | (*Point)(nil), // 1: route.Point 424 | (*Rectangle)(nil), // 2: route.Rectangle 425 | (*Feature)(nil), // 3: route.Feature 426 | (*RouteSummary)(nil), // 4: route.RouteSummary 427 | (*RecommendationRequest)(nil), // 5: route.RecommendationRequest 428 | } 429 | var file_route_proto_depIdxs = []int32{ 430 | 1, // 0: route.Rectangle.lo:type_name -> route.Point 431 | 1, // 1: route.Rectangle.hi:type_name -> route.Point 432 | 1, // 2: route.Feature.location:type_name -> route.Point 433 | 0, // 3: route.RecommendationRequest.mode:type_name -> route.RecommendationMode 434 | 1, // 4: route.RecommendationRequest.point:type_name -> route.Point 435 | 1, // 5: route.RouteGuide.GetFeature:input_type -> route.Point 436 | 2, // 6: route.RouteGuide.ListFeatures:input_type -> route.Rectangle 437 | 1, // 7: route.RouteGuide.RecordRoute:input_type -> route.Point 438 | 5, // 8: route.RouteGuide.Recommend:input_type -> route.RecommendationRequest 439 | 3, // 9: route.RouteGuide.GetFeature:output_type -> route.Feature 440 | 3, // 10: route.RouteGuide.ListFeatures:output_type -> route.Feature 441 | 4, // 11: route.RouteGuide.RecordRoute:output_type -> route.RouteSummary 442 | 3, // 12: route.RouteGuide.Recommend:output_type -> route.Feature 443 | 9, // [9:13] is the sub-list for method output_type 444 | 5, // [5:9] is the sub-list for method input_type 445 | 5, // [5:5] is the sub-list for extension type_name 446 | 5, // [5:5] is the sub-list for extension extendee 447 | 0, // [0:5] is the sub-list for field type_name 448 | } 449 | 450 | func init() { file_route_proto_init() } 451 | func file_route_proto_init() { 452 | if File_route_proto != nil { 453 | return 454 | } 455 | if !protoimpl.UnsafeEnabled { 456 | file_route_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 457 | switch v := v.(*Point); i { 458 | case 0: 459 | return &v.state 460 | case 1: 461 | return &v.sizeCache 462 | case 2: 463 | return &v.unknownFields 464 | default: 465 | return nil 466 | } 467 | } 468 | file_route_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 469 | switch v := v.(*Rectangle); i { 470 | case 0: 471 | return &v.state 472 | case 1: 473 | return &v.sizeCache 474 | case 2: 475 | return &v.unknownFields 476 | default: 477 | return nil 478 | } 479 | } 480 | file_route_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 481 | switch v := v.(*Feature); i { 482 | case 0: 483 | return &v.state 484 | case 1: 485 | return &v.sizeCache 486 | case 2: 487 | return &v.unknownFields 488 | default: 489 | return nil 490 | } 491 | } 492 | file_route_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 493 | switch v := v.(*RouteSummary); i { 494 | case 0: 495 | return &v.state 496 | case 1: 497 | return &v.sizeCache 498 | case 2: 499 | return &v.unknownFields 500 | default: 501 | return nil 502 | } 503 | } 504 | file_route_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 505 | switch v := v.(*RecommendationRequest); i { 506 | case 0: 507 | return &v.state 508 | case 1: 509 | return &v.sizeCache 510 | case 2: 511 | return &v.unknownFields 512 | default: 513 | return nil 514 | } 515 | } 516 | } 517 | type x struct{} 518 | out := protoimpl.TypeBuilder{ 519 | File: protoimpl.DescBuilder{ 520 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 521 | RawDescriptor: file_route_proto_rawDesc, 522 | NumEnums: 1, 523 | NumMessages: 5, 524 | NumExtensions: 0, 525 | NumServices: 1, 526 | }, 527 | GoTypes: file_route_proto_goTypes, 528 | DependencyIndexes: file_route_proto_depIdxs, 529 | EnumInfos: file_route_proto_enumTypes, 530 | MessageInfos: file_route_proto_msgTypes, 531 | }.Build() 532 | File_route_proto = out.File 533 | file_route_proto_rawDesc = nil 534 | file_route_proto_goTypes = nil 535 | file_route_proto_depIdxs = nil 536 | } 537 | -------------------------------------------------------------------------------- /grpc-example/route/route.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | 4 | option go_package = "github.com/HanFa/learn-go/grpc-example/route"; 5 | 6 | package route; 7 | 8 | /* 9 | 描述一个向导服务,服务名为RouteGuide 10 | 定义四种不同的信息类型分别为Point, Rectangle, Feature, RouteSummary以及Chat。 11 | 定义四个方法 12 | 1. GetFeature (输入为一个Point,返回这个点的Feature) 13 | 2. ListFeatures (输入为一个Rectangle,输出流这个区域内所有的Feature) 14 | 3. RecordRoute (输入流为每个时间点的位置Point,返回一个RouteSummary) 15 | 4. Recommend (输入流RecommendationRequest,输出流Feature) 16 | */ 17 | 18 | message Point { 19 | int32 latitude = 1; 20 | int32 longitude = 2; 21 | } 22 | 23 | message Rectangle { 24 | Point lo = 1; 25 | Point hi = 2; 26 | } 27 | 28 | message Feature { 29 | string name = 1; 30 | Point location = 2; 31 | } 32 | 33 | message RouteSummary { 34 | int32 point_count = 1; 35 | int32 distance = 2; 36 | int32 elapsed_time = 3; 37 | } 38 | 39 | enum RecommendationMode { 40 | GetFarthest = 0; 41 | GetNearest = 1; 42 | } 43 | 44 | message RecommendationRequest { 45 | RecommendationMode mode = 1; 46 | Point point = 2; 47 | } 48 | 49 | service RouteGuide { 50 | // unary 51 | rpc GetFeature(Point) returns (Feature) {} 52 | 53 | // server side streaming 54 | rpc ListFeatures(Rectangle) returns (stream Feature) {} 55 | 56 | // client side streaming 57 | rpc RecordRoute(stream Point) returns (RouteSummary) {} 58 | 59 | // bidirectional streaming 60 | rpc Recommend(stream RecommendationRequest) returns (stream Feature) {} 61 | 62 | } -------------------------------------------------------------------------------- /grpc-example/route/route_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | 3 | package route 4 | 5 | import ( 6 | context "context" 7 | grpc "google.golang.org/grpc" 8 | codes "google.golang.org/grpc/codes" 9 | status "google.golang.org/grpc/status" 10 | ) 11 | 12 | // This is a compile-time assertion to ensure that this generated file 13 | // is compatible with the grpc package it is being compiled against. 14 | // Requires gRPC-Go v1.32.0 or later. 15 | const _ = grpc.SupportPackageIsVersion7 16 | 17 | // RouteGuideClient is the client API for RouteGuide service. 18 | // 19 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 20 | type RouteGuideClient interface { 21 | // unary 22 | GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error) 23 | // server side streaming 24 | ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (RouteGuide_ListFeaturesClient, error) 25 | // client side streaming 26 | RecordRoute(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecordRouteClient, error) 27 | // bidirectional streaming 28 | Recommend(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecommendClient, error) 29 | } 30 | 31 | type routeGuideClient struct { 32 | cc grpc.ClientConnInterface 33 | } 34 | 35 | func NewRouteGuideClient(cc grpc.ClientConnInterface) RouteGuideClient { 36 | return &routeGuideClient{cc} 37 | } 38 | 39 | func (c *routeGuideClient) GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error) { 40 | out := new(Feature) 41 | err := c.cc.Invoke(ctx, "/route.RouteGuide/GetFeature", in, out, opts...) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return out, nil 46 | } 47 | 48 | func (c *routeGuideClient) ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (RouteGuide_ListFeaturesClient, error) { 49 | stream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[0], "/route.RouteGuide/ListFeatures", opts...) 50 | if err != nil { 51 | return nil, err 52 | } 53 | x := &routeGuideListFeaturesClient{stream} 54 | if err := x.ClientStream.SendMsg(in); err != nil { 55 | return nil, err 56 | } 57 | if err := x.ClientStream.CloseSend(); err != nil { 58 | return nil, err 59 | } 60 | return x, nil 61 | } 62 | 63 | type RouteGuide_ListFeaturesClient interface { 64 | Recv() (*Feature, error) 65 | grpc.ClientStream 66 | } 67 | 68 | type routeGuideListFeaturesClient struct { 69 | grpc.ClientStream 70 | } 71 | 72 | func (x *routeGuideListFeaturesClient) Recv() (*Feature, error) { 73 | m := new(Feature) 74 | if err := x.ClientStream.RecvMsg(m); err != nil { 75 | return nil, err 76 | } 77 | return m, nil 78 | } 79 | 80 | func (c *routeGuideClient) RecordRoute(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecordRouteClient, error) { 81 | stream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[1], "/route.RouteGuide/RecordRoute", opts...) 82 | if err != nil { 83 | return nil, err 84 | } 85 | x := &routeGuideRecordRouteClient{stream} 86 | return x, nil 87 | } 88 | 89 | type RouteGuide_RecordRouteClient interface { 90 | Send(*Point) error 91 | CloseAndRecv() (*RouteSummary, error) 92 | grpc.ClientStream 93 | } 94 | 95 | type routeGuideRecordRouteClient struct { 96 | grpc.ClientStream 97 | } 98 | 99 | func (x *routeGuideRecordRouteClient) Send(m *Point) error { 100 | return x.ClientStream.SendMsg(m) 101 | } 102 | 103 | func (x *routeGuideRecordRouteClient) CloseAndRecv() (*RouteSummary, error) { 104 | if err := x.ClientStream.CloseSend(); err != nil { 105 | return nil, err 106 | } 107 | m := new(RouteSummary) 108 | if err := x.ClientStream.RecvMsg(m); err != nil { 109 | return nil, err 110 | } 111 | return m, nil 112 | } 113 | 114 | func (c *routeGuideClient) Recommend(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecommendClient, error) { 115 | stream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[2], "/route.RouteGuide/Recommend", opts...) 116 | if err != nil { 117 | return nil, err 118 | } 119 | x := &routeGuideRecommendClient{stream} 120 | return x, nil 121 | } 122 | 123 | type RouteGuide_RecommendClient interface { 124 | Send(*RecommendationRequest) error 125 | Recv() (*Feature, error) 126 | grpc.ClientStream 127 | } 128 | 129 | type routeGuideRecommendClient struct { 130 | grpc.ClientStream 131 | } 132 | 133 | func (x *routeGuideRecommendClient) Send(m *RecommendationRequest) error { 134 | return x.ClientStream.SendMsg(m) 135 | } 136 | 137 | func (x *routeGuideRecommendClient) Recv() (*Feature, error) { 138 | m := new(Feature) 139 | if err := x.ClientStream.RecvMsg(m); err != nil { 140 | return nil, err 141 | } 142 | return m, nil 143 | } 144 | 145 | // RouteGuideServer is the server API for RouteGuide service. 146 | // All implementations must embed UnimplementedRouteGuideServer 147 | // for forward compatibility 148 | type RouteGuideServer interface { 149 | // unary 150 | GetFeature(context.Context, *Point) (*Feature, error) 151 | // server side streaming 152 | ListFeatures(*Rectangle, RouteGuide_ListFeaturesServer) error 153 | // client side streaming 154 | RecordRoute(RouteGuide_RecordRouteServer) error 155 | // bidirectional streaming 156 | Recommend(RouteGuide_RecommendServer) error 157 | mustEmbedUnimplementedRouteGuideServer() 158 | } 159 | 160 | // UnimplementedRouteGuideServer must be embedded to have forward compatible implementations. 161 | type UnimplementedRouteGuideServer struct { 162 | } 163 | 164 | func (UnimplementedRouteGuideServer) GetFeature(context.Context, *Point) (*Feature, error) { 165 | return nil, status.Errorf(codes.Unimplemented, "method GetFeature not implemented") 166 | } 167 | func (UnimplementedRouteGuideServer) ListFeatures(*Rectangle, RouteGuide_ListFeaturesServer) error { 168 | return status.Errorf(codes.Unimplemented, "method ListFeatures not implemented") 169 | } 170 | func (UnimplementedRouteGuideServer) RecordRoute(RouteGuide_RecordRouteServer) error { 171 | return status.Errorf(codes.Unimplemented, "method RecordRoute not implemented") 172 | } 173 | func (UnimplementedRouteGuideServer) Recommend(RouteGuide_RecommendServer) error { 174 | return status.Errorf(codes.Unimplemented, "method Recommend not implemented") 175 | } 176 | func (UnimplementedRouteGuideServer) mustEmbedUnimplementedRouteGuideServer() {} 177 | 178 | // UnsafeRouteGuideServer may be embedded to opt out of forward compatibility for this service. 179 | // Use of this interface is not recommended, as added methods to RouteGuideServer will 180 | // result in compilation errors. 181 | type UnsafeRouteGuideServer interface { 182 | mustEmbedUnimplementedRouteGuideServer() 183 | } 184 | 185 | func RegisterRouteGuideServer(s grpc.ServiceRegistrar, srv RouteGuideServer) { 186 | s.RegisterService(&RouteGuide_ServiceDesc, srv) 187 | } 188 | 189 | func _RouteGuide_GetFeature_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 190 | in := new(Point) 191 | if err := dec(in); err != nil { 192 | return nil, err 193 | } 194 | if interceptor == nil { 195 | return srv.(RouteGuideServer).GetFeature(ctx, in) 196 | } 197 | info := &grpc.UnaryServerInfo{ 198 | Server: srv, 199 | FullMethod: "/route.RouteGuide/GetFeature", 200 | } 201 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 202 | return srv.(RouteGuideServer).GetFeature(ctx, req.(*Point)) 203 | } 204 | return interceptor(ctx, in, info, handler) 205 | } 206 | 207 | func _RouteGuide_ListFeatures_Handler(srv interface{}, stream grpc.ServerStream) error { 208 | m := new(Rectangle) 209 | if err := stream.RecvMsg(m); err != nil { 210 | return err 211 | } 212 | return srv.(RouteGuideServer).ListFeatures(m, &routeGuideListFeaturesServer{stream}) 213 | } 214 | 215 | type RouteGuide_ListFeaturesServer interface { 216 | Send(*Feature) error 217 | grpc.ServerStream 218 | } 219 | 220 | type routeGuideListFeaturesServer struct { 221 | grpc.ServerStream 222 | } 223 | 224 | func (x *routeGuideListFeaturesServer) Send(m *Feature) error { 225 | return x.ServerStream.SendMsg(m) 226 | } 227 | 228 | func _RouteGuide_RecordRoute_Handler(srv interface{}, stream grpc.ServerStream) error { 229 | return srv.(RouteGuideServer).RecordRoute(&routeGuideRecordRouteServer{stream}) 230 | } 231 | 232 | type RouteGuide_RecordRouteServer interface { 233 | SendAndClose(*RouteSummary) error 234 | Recv() (*Point, error) 235 | grpc.ServerStream 236 | } 237 | 238 | type routeGuideRecordRouteServer struct { 239 | grpc.ServerStream 240 | } 241 | 242 | func (x *routeGuideRecordRouteServer) SendAndClose(m *RouteSummary) error { 243 | return x.ServerStream.SendMsg(m) 244 | } 245 | 246 | func (x *routeGuideRecordRouteServer) Recv() (*Point, error) { 247 | m := new(Point) 248 | if err := x.ServerStream.RecvMsg(m); err != nil { 249 | return nil, err 250 | } 251 | return m, nil 252 | } 253 | 254 | func _RouteGuide_Recommend_Handler(srv interface{}, stream grpc.ServerStream) error { 255 | return srv.(RouteGuideServer).Recommend(&routeGuideRecommendServer{stream}) 256 | } 257 | 258 | type RouteGuide_RecommendServer interface { 259 | Send(*Feature) error 260 | Recv() (*RecommendationRequest, error) 261 | grpc.ServerStream 262 | } 263 | 264 | type routeGuideRecommendServer struct { 265 | grpc.ServerStream 266 | } 267 | 268 | func (x *routeGuideRecommendServer) Send(m *Feature) error { 269 | return x.ServerStream.SendMsg(m) 270 | } 271 | 272 | func (x *routeGuideRecommendServer) Recv() (*RecommendationRequest, error) { 273 | m := new(RecommendationRequest) 274 | if err := x.ServerStream.RecvMsg(m); err != nil { 275 | return nil, err 276 | } 277 | return m, nil 278 | } 279 | 280 | // RouteGuide_ServiceDesc is the grpc.ServiceDesc for RouteGuide service. 281 | // It's only intended for direct use with grpc.RegisterService, 282 | // and not to be introspected or modified (even as a copy) 283 | var RouteGuide_ServiceDesc = grpc.ServiceDesc{ 284 | ServiceName: "route.RouteGuide", 285 | HandlerType: (*RouteGuideServer)(nil), 286 | Methods: []grpc.MethodDesc{ 287 | { 288 | MethodName: "GetFeature", 289 | Handler: _RouteGuide_GetFeature_Handler, 290 | }, 291 | }, 292 | Streams: []grpc.StreamDesc{ 293 | { 294 | StreamName: "ListFeatures", 295 | Handler: _RouteGuide_ListFeatures_Handler, 296 | ServerStreams: true, 297 | }, 298 | { 299 | StreamName: "RecordRoute", 300 | Handler: _RouteGuide_RecordRoute_Handler, 301 | ClientStreams: true, 302 | }, 303 | { 304 | StreamName: "Recommend", 305 | Handler: _RouteGuide_Recommend_Handler, 306 | ServerStreams: true, 307 | ClientStreams: true, 308 | }, 309 | }, 310 | Metadata: "route.proto", 311 | } 312 | -------------------------------------------------------------------------------- /reflection-example/1-interface-values-to-reflection-objects.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func printMeta(obj interface{}) { 9 | // pair: 10 | t := reflect.TypeOf(obj) 11 | n := t.Name() 12 | k := t.Kind() 13 | v := reflect.ValueOf(obj) 14 | fmt.Printf("Type: %s Type.Name: %s Kind: %s Value: %v\n", t, n, k, v) 15 | } 16 | 17 | type handler func(int, int) int 18 | 19 | func main() { 20 | 21 | var intVar int64 = 10 22 | stringVar := "hello" 23 | type book struct { 24 | name string 25 | pages int 26 | } 27 | sum := func(a, b int) int { 28 | return a + b 29 | } 30 | var sub handler = func(a, b int) int { 31 | return a - b 32 | } 33 | sli := make([]int, 5) 34 | 35 | printMeta(intVar) 36 | printMeta(stringVar) 37 | printMeta(book{ 38 | name: "harry potter", 39 | pages: 500, 40 | }) 41 | printMeta(sum) 42 | printMeta(sub) 43 | printMeta(sli) 44 | } 45 | -------------------------------------------------------------------------------- /reflection-example/2-reflection-objects-to-interface-values.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type student struct { 9 | Name string 10 | } 11 | 12 | func main() { 13 | // FIRST EXAMPLE SHOWING CONVERT REFLECT.VALUE TO FLOAT 14 | floatVar := 3.14 15 | v := reflect.ValueOf(floatVar) 16 | newFloat := v.Interface().(float64) 17 | fmt.Println(newFloat + 1.2) 18 | 19 | // second example showing convert Reflect.Value to slice 20 | sliceVar := make([]int, 5) 21 | v = reflect.ValueOf(sliceVar) 22 | v = reflect.Append(v, reflect.ValueOf(2)) 23 | newSlice := v.Interface().([]int) 24 | newSlice = append(newSlice, 4) 25 | fmt.Println(newSlice) 26 | 27 | // third example showing convert Reflect.Value to student 28 | stuPtr := reflect.New(reflect.TypeOf(student{})) 29 | stu := stuPtr.Elem() 30 | nameField := stu.FieldByName("Name") 31 | if nameField.IsValid() { 32 | if nameField.CanSet() { 33 | nameField.SetString("chong") 34 | } 35 | realStudent := stu.Interface().(student) 36 | fmt.Println(realStudent) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /reflection-example/3-setability-modify-reflection-objects.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | func main() { 9 | fVar := 3.14 10 | v := reflect.ValueOf(fVar) 11 | fmt.Printf("is float canSet: %v canAddr %v\n", v.CanSet(), v.CanAddr()) 12 | v.SetFloat(221232.12) 13 | vp := reflect.ValueOf(&fVar) 14 | fmt.Printf("is float canSet: %v canAddr %v\n", vp.Elem().CanSet(), vp.Elem().CanAddr()) 15 | vp.Elem().SetFloat(2.33333) 16 | 17 | println(fVar) 18 | } 19 | -------------------------------------------------------------------------------- /reflection-example/4-invoke-methods-from-reflect-obj.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type Student struct { 9 | name string 10 | } 11 | 12 | func (s Student) DoHomework(number int) { 13 | fmt.Printf("%s is doing homework %d\n", s.name, number) 14 | } 15 | 16 | func main() { 17 | // use reflect to invoke the DoHomework of a student 18 | s := Student{name: "heli"} 19 | v := reflect.ValueOf(s) 20 | methodV := v.MethodByName("DoHomework") 21 | if methodV.IsValid() { 22 | in := []reflect.Value{reflect.ValueOf(55)} 23 | methodV.Call(in) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /reflection-example/5-make-func-from-reflect-obj.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | func makeTimeFunc(f interface{}) interface{} { 10 | tf := reflect.TypeOf(f) 11 | vf := reflect.ValueOf(f) 12 | 13 | if tf.Kind() != reflect.Func { 14 | panic("expect a function") 15 | } 16 | wrapper := reflect.MakeFunc(tf, func(args []reflect.Value) (result []reflect.Value) { 17 | start := time.Now() 18 | result = vf.Call(args) 19 | end := time.Now() 20 | fmt.Printf("The function takes %v\n", end.Sub(start)) 21 | return result 22 | }) 23 | return wrapper.Interface() 24 | } 25 | 26 | func TimeMe() { 27 | time.Sleep(1 * time.Second) 28 | } 29 | 30 | func main() { 31 | timedFunc := makeTimeFunc(TimeMe).(func()) 32 | timedFunc() 33 | } 34 | -------------------------------------------------------------------------------- /reflection-example/reflection-examples.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type User struct { 9 | name string 10 | age int 11 | } 12 | 13 | func (u User) PrintName() { 14 | fmt.Println(u.name) 15 | } 16 | 17 | func (u User) PrintAge() { 18 | fmt.Println(u.age) 19 | } 20 | 21 | type Aggregator func(int, int) int 22 | 23 | var ( 24 | user = User{ 25 | name: "heli", 26 | age: 24, 27 | } 28 | 29 | add Aggregator = func(a, b int) int { 30 | return a + b 31 | } 32 | sub Aggregator = func(a, b int) int { 33 | return a - b 34 | } 35 | ) 36 | 37 | func inspect(variable interface{}) { 38 | t := reflect.TypeOf(variable) 39 | v := reflect.ValueOf(variable) 40 | 41 | if t.Kind() == reflect.Struct { 42 | // print its fields 43 | fmt.Printf("--------- fields %d ----------\n", t.NumField()) 44 | for idx := 0; idx < t.NumField(); idx++ { 45 | fieldType := t.Field(idx) 46 | fieldVal := v.Field(idx) 47 | fmt.Printf("\t %v = %v\n", fieldType.Name, fieldVal) 48 | } 49 | 50 | // iterate its methods 51 | fmt.Printf("--------- methods %d ----------\n", t.NumMethod()) 52 | for idx := 0; idx < t.NumMethod(); idx++ { 53 | methodType := t.Method(idx) 54 | fmt.Printf("\t method_name=%s input_num=%d, output_num=%d\n", 55 | methodType.Name, 56 | methodType.Type.NumIn(), methodType.Type.NumOut()) 57 | } 58 | } else if t.Kind() == reflect.Func { 59 | fmt.Printf("this function has %d inputs and %d outputs\n", t.NumIn(), t.NumOut()) 60 | } 61 | fmt.Printf("\n\n") 62 | } 63 | 64 | func main() { 65 | //inspect(user) 66 | inspect(add) 67 | inspect(sub) 68 | } 69 | -------------------------------------------------------------------------------- /testing-example/concurrent/concurrent.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | func atomicIncCounter(counter *int64, wg *sync.WaitGroup) { 9 | defer wg.Done() 10 | for i := 0; i < 10000; i++ { 11 | atomic.AddInt64(counter, 1) 12 | } 13 | } 14 | 15 | func mutexIncCounter(counter *int64, wg *sync.WaitGroup, mtx *sync.Mutex) { 16 | defer wg.Done() 17 | for i := 0; i < 10000; i++ { 18 | mtx.Lock() 19 | *counter++ 20 | mtx.Unlock() 21 | } 22 | } 23 | 24 | func ConcurrentAtomicAdd() int64 { 25 | wg := sync.WaitGroup{} 26 | wg.Add(2) 27 | var counter int64 = 0 28 | go atomicIncCounter(&counter, &wg) 29 | go atomicIncCounter(&counter, &wg) 30 | wg.Wait() 31 | return counter 32 | } 33 | 34 | func ConcurrentMutexAdd() int64 { 35 | wg := sync.WaitGroup{} 36 | wg.Add(2) 37 | var counter int64 = 0 38 | var mtx sync.Mutex 39 | go mutexIncCounter(&counter, &wg, &mtx) 40 | go mutexIncCounter(&counter, &wg, &mtx) 41 | wg.Wait() 42 | return counter 43 | } 44 | 45 | func main() { 46 | println(ConcurrentAtomicAdd()) 47 | println(ConcurrentMutexAdd()) 48 | } 49 | -------------------------------------------------------------------------------- /testing-example/concurrent/concurrent_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkConcurrentAtomicAdd(b *testing.B) { 6 | b.ResetTimer() 7 | for i := 0; i < b.N; i++ { 8 | ConcurrentAtomicAdd() 9 | } 10 | } 11 | 12 | func BenchmarkConcurrentMutexAdd(b *testing.B) { 13 | b.ResetTimer() 14 | for i := 0; i < b.N; i++ { 15 | ConcurrentMutexAdd() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /testing-example/server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/HanFa/learn-go/testing-example/server 2 | 3 | go 1.16 -------------------------------------------------------------------------------- /testing-example/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | http.HandleFunc("/double", doubleHandler) 12 | log.Fatalln(http.ListenAndServe(":4000", nil)) 13 | } 14 | 15 | func doubleHandler(w http.ResponseWriter, r *http.Request) { 16 | text := r.FormValue("v") 17 | 18 | if text == "" { 19 | http.Error(w, "missing value", http.StatusBadRequest) 20 | return 21 | } 22 | 23 | v, err := strconv.Atoi(text) 24 | if err != nil { 25 | http.Error(w, "not a number: "+text, http.StatusBadRequest) 26 | return 27 | } 28 | 29 | if _, err = fmt.Fprintln(w, v*2); err != nil { 30 | http.Error(w, "cannot write to response", http.StatusBadRequest) 31 | return 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /testing-example/server/server_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "net/http/httptest" 7 | "strconv" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | func TestDoubleHandler(t *testing.T) { 13 | 14 | testCases := []struct { 15 | name string 16 | input string 17 | result int 18 | status int 19 | err string 20 | }{ 21 | {name: "double of two", input: "2", result: 4, status: http.StatusOK, err: ""}, 22 | {name: "double of nine", input: "9", result: 18, status: http.StatusOK, err: ""}, 23 | {name: "double of nil", input: "", status: http.StatusBadRequest, err: "missing value"}, 24 | } 25 | 26 | for _, testCase := range testCases { 27 | t.Run(testCase.name, func(t *testing.T) { 28 | req, err := http.NewRequest(http.MethodGet, "localhost:4000/double?v="+testCase.input, nil) 29 | if err != nil { 30 | t.Fatalf("could not create a new request: %v, err: %v", req, err) 31 | } 32 | 33 | rec := httptest.NewRecorder() 34 | doubleHandler(rec, req) 35 | res := rec.Result() 36 | 37 | if res.StatusCode != testCase.status { 38 | t.Errorf("received status code %d, expect %d", res.StatusCode, testCase.status) 39 | return 40 | } 41 | 42 | respBytes, err := io.ReadAll(res.Body) 43 | if err != nil { 44 | t.Fatalf("cannot read all from the response body, err: %v", err) 45 | } 46 | defer res.Body.Close() 47 | 48 | trimedResult := strings.TrimSpace(string(respBytes)) 49 | 50 | if res.StatusCode != http.StatusOK { 51 | // check the error message 52 | if trimedResult != testCase.err { 53 | t.Errorf("received error message %s, expect %s", trimedResult, testCase.err) 54 | } 55 | return 56 | } 57 | 58 | // compare the returned value 59 | doubleVal, err := strconv.Atoi(trimedResult) 60 | if err != nil { 61 | t.Errorf("cannot convert response body to int, err: %v", err) 62 | return 63 | } 64 | 65 | if doubleVal != testCase.result { 66 | t.Errorf("received result %d, expected %d", doubleVal, testCase.result) 67 | } 68 | }) 69 | } 70 | } 71 | --------------------------------------------------------------------------------