├── LICENSE ├── README.md ├── base.go ├── decorator.go ├── error_handle.go ├── functional_options.go ├── generation.go ├── ioc.go ├── map_reduce.go ├── pipeline.go └── visitor.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 roseduan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-patterns 2 | Go 语言编程模式最佳实践,来源于耗子叔的博客分享总结,十分感谢。 3 | 4 | 也欢迎访问耗子叔的博客学习更多知识:[https://coolshell.cn](https://coolshell.cn/) 5 | 6 | *** 7 | 8 | ### 一、切片,接口,性能 9 | 10 | [base.go](https://github.com/roseduan/go-patterns/blob/main/base.go) 11 | 12 | 参考阅读: 13 | 14 | [Effective Go](https://golang.org/doc/effective_go.html) 15 | 16 | [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) 17 | 18 | [50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs](http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/) 19 | 20 | [Go Advice](https://github.com/cristaloleg/go-advice) 21 | 22 | [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) 23 | 24 | ### 二、错误处理 25 | 26 | [error_handle.go](https://github.com/roseduan/go-patterns/blob/main/error_handle.go) 27 | 28 | 参考阅读: 29 | 30 | [Golang Error Handling lesson by Rob Pike](http://jxck.hatenablog.com/entry/golang-error-handling-lesson-by-rob-pike) 31 | 32 | [Errors are values](https://blog.golang.org/errors-are-values) 33 | 34 | [Error handling and Go](https://blog.golang.org/error-handling-and-go) 35 | 36 | [Working with Errors in Go 1.13](https://blog.golang.org/go1.13-errors) 37 | 38 | [Golang: Six Error Handling techniques to help you write elegant code](https://medium.com/higher-order-functions/golang-six-error-handling-techniques-to-help-you-write-elegant-code-8e6363e6d2b) 39 | 40 | ### 三、Functional Options 41 | 42 | [functional_options.go](https://github.com/roseduan/go-patterns/blob/main/functional_options.go) 43 | 44 | 参考阅读: 45 | 46 | [Self-referential functions and the design of options](https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html) 47 | 48 | [Implementing the Options Pattern in Golang](https://www.sohamkamani.com/golang/options-pattern/) 49 | 50 | ### 四、委托和控制反转 51 | 52 | [ioc.go](https://github.com/roseduan/go-patterns/blob/main/ioc.go) 53 | 54 | 参考阅读: 55 | 56 | [IOC/DIP其实是一种管理思想](https://coolshell.cn/articles/9949.html) 57 | 58 | [Dependency Injection and IoC Container in Go](https://medium.com/@miladrahimi/dependency-injection-and-ioc-container-in-go-golang-928c5c416f28) 59 | 60 | ### 五、Map-Reduce 61 | 62 | [map_reduce.go](https://github.com/roseduan/go-patterns/blob/main/map_reduce.go) 63 | 64 | 参考阅读: 65 | 66 | [官方文档:反射 reflect 包介绍](https://golang.org/pkg/reflect/) 67 | 68 | [The Laws of Reflection](https://blog.golang.org/laws-of-reflection) 69 | 70 | [Simple apply/filter/reduce package — Rob Pike](https://github.com/robpike/filter) 71 | 72 | ### 六、Go Generation 73 | 74 | [generation.go](https://github.com/roseduan/go-patterns/blob/main/generation.go) 75 | 76 | ### 七、修饰器模式 77 | 78 | [decorator.go](https://github.com/roseduan/go-patterns/blob/main/decorator.go) 79 | 80 | 参考阅读: 81 | 82 | [函数式编程](https://coolshell.cn/articles/10822.html) 83 | 84 | [go-decorator-pattern](https://github.com/alex-leonhardt/go-decorator-pattern) 85 | 86 | [go-decorator-pattern](https://github.com/alex-leonhardt/go-decorator-pattern) 87 | 88 | ### 八、Pipeline 89 | 90 | [pipeline.go](https://github.com/roseduan/go-patterns/blob/main/pipeline.go) 91 | 92 | 参考阅读: 93 | 94 | [Go Concurrency Patterns: Pipelines and cancellation](https://blog.golang.org/pipelines) 95 | 96 | ### 九、Visitor 模式 97 | 98 | [visitor.go](https://github.com/roseduan/go-patterns/blob/main/visitor.go) 99 | 100 | 参考阅读: 101 | 102 | [Visitor Design Pattern in Golang](https://medium.com/@felipedutratine/visitor-design-pattern-in-golang-3c142a12945a) 103 | 104 | [Visitor in Golang](https://gist.github.com/francoishill/f0624e7760aacdc96b42) 105 | 106 | -------------------------------------------------------------------------------- /base.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | //切片,接口,性能 9 | 10 | //1.切片的内部结构,源码在 runtime/slice.go 中可查看 11 | //type slice struct { 12 | // array unsafe.Pointer 13 | // len int 14 | // cap int 15 | //} 16 | 17 | //2.接口编程 18 | 19 | //一个简单的例子 20 | type Person struct { 21 | Name string 22 | Sexual string 23 | Age int 24 | } 25 | 26 | //下面这两个方法有什么区别? 27 | func (p *Person) Print() { 28 | fmt.Printf("Name=%s, Sexual=%s, Age=%d", p.Name, p.Sexual, p.Age) 29 | } 30 | 31 | func PrintPerson(p *Person) { 32 | fmt.Printf("Name=%s, Sexual=%s, Age=%d", p.Name, p.Sexual, p.Age) 33 | } 34 | 35 | //再来看另一个例子 36 | type Country struct { 37 | Name string 38 | } 39 | 40 | type City struct { 41 | Name string 42 | } 43 | 44 | type Printable interface { 45 | PrintStr() 46 | } 47 | 48 | func (c *Country) PrintStr() { 49 | fmt.Println(c.Name) 50 | } 51 | 52 | func (c *City) PrintStr() { 53 | fmt.Println(c.Name) 54 | } 55 | 56 | //使用结构体嵌入改进上面的例子 57 | type WithName struct { 58 | Name string 59 | } 60 | 61 | type Dog struct { 62 | WithName 63 | } 64 | 65 | type Cat struct { 66 | WithName 67 | } 68 | 69 | func (w *WithName) PrintStr() { 70 | fmt.Println(w.Name) 71 | } 72 | 73 | //再简化上面的例子 74 | type Stringable interface { 75 | ToString() string 76 | } 77 | 78 | func PrintName(s Stringable) { 79 | fmt.Println(s.ToString()) 80 | } 81 | 82 | func (c *Country) ToString() string { 83 | return c.Name 84 | } 85 | 86 | func (c *City) ToString() string { 87 | return c.Name 88 | } 89 | 90 | //3.性能方面的小建议 91 | //如果需要把数字转换成字符串,使用 strconv.Itoa() 比 fmt.Sprintf() 要快一倍左右 92 | //尽可能避免把String转成[]Byte ,这个转换会导致性能下降 93 | //如果在 for-loop 里对某个 Slice 使用 append(),请先把 Slice 的容量扩充到位,这样可以避免内存重新分配以及系统自动按 2 的 N 次方幂进行扩展但又用不到的情况,从而避免浪费内存 94 | //使用StringBuffer 或是StringBuild 来拼接字符串,性能会比使用 + 或 +=高三到四个数量级 95 | //尽可能使用并发的 goroutine,然后使用 sync.WaitGroup 来同步分片操作 96 | //避免在热代码中进行内存分配,这样会导致 gc 很忙 97 | //尽可能使用 sync.Pool 来重用对象 98 | //使用 lock-free 的操作,避免使用 mutex,尽可能使用 sync/Atomic包(关于无锁编程的相关话题,可参看《无锁队列实现》或《无锁 Hashmap 实现》) 99 | // reference: https://coolshell.cn/articles/8239.html https://coolshell.cn/articles/9703.html 100 | //使用 I/O 缓冲,I/O 是个非常非常慢的操作,使用 bufio.NewWrite() 和 bufio.NewReader() 可以带来更高的性能 101 | //对于在 for-loop 里的固定的正则表达式,一定要使用 regexp.Compile() 编译正则表达式。性能会提升两个数量级 102 | //考虑使用 protobuf 或 msgp 而不是 JSON,因为 JSON 的序列化和反序列化里使用了反射 103 | //使用 Map 的时候,使用整型的 key 会比字符串的要快,因为整型比较比字符串比较要快 104 | 105 | func main() { 106 | fmt.Println("--------切片实践--------") 107 | nums := make([]int, 5) 108 | nums[0] = 10 109 | nums[1] = 20 110 | nums[2] = 25 111 | 112 | fmt.Println("nums = ", nums) 113 | another := nums[:3] 114 | 115 | //another和nums共享同一个底层数组,因此这里的改动会影响到nums 116 | another[0] = 100 117 | fmt.Println("nums = ", nums) 118 | 119 | //如果新的切片发生了扩容,那么则不会影响到原来的切片了 120 | arr := make([]int, 3) 121 | arr[0] = 0 122 | arr[1] = 1 123 | arr[2] = 2 124 | 125 | arr2 := arr[:] 126 | arr2 = append(arr2, 10, 20) 127 | arr2[0] = 100 128 | fmt.Println(arr, arr2) 129 | 130 | //切片之间的比较可以使用 reflect.DeepEqual 131 | v1 := []int{} 132 | v2 := []int{} 133 | fmt.Println(reflect.DeepEqual(v1, v2)) //true 134 | 135 | m1 := map[int]string{1: "a", 2: "b", 3: "c"} 136 | m2 := map[int]string{2: "b", 3: "c", 1: "a"} 137 | fmt.Println(reflect.DeepEqual(m1, m2)) //true 138 | 139 | sli1 := []int{1, 2, 3} 140 | sli2 := []int{1, 2, 3} 141 | fmt.Println(reflect.DeepEqual(sli1, sli2)) //true 142 | 143 | fmt.Println("--------接口编程实践--------") 144 | c := Country{"China"} 145 | c.PrintStr() 146 | 147 | city := City{"Shanghai"} 148 | city.PrintStr() 149 | 150 | bobby := Dog{WithName{"Bobby"}} 151 | mimi := Cat{WithName{"mimi"}} 152 | bobby.PrintStr() 153 | mimi.PrintStr() 154 | 155 | PrintName(&c) 156 | PrintName(&city) 157 | } 158 | -------------------------------------------------------------------------------- /decorator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "reflect" 8 | "runtime" 9 | "time" 10 | ) 11 | 12 | //修饰器模式 13 | 14 | 15 | //一个简单的修饰器函数 16 | func decorator(fn func(s string)) func (s string) { 17 | return func(s string) { 18 | fmt.Println("started") 19 | fn(s) 20 | fmt.Println("done") 21 | } 22 | } 23 | 24 | func Hello(s string) { 25 | fmt.Println(s) 26 | } 27 | 28 | //一个计算函数运行时间的例子 29 | type SumFunc func(int64, int64) int64 30 | 31 | func getFuncName(i interface{}) string { 32 | return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() 33 | } 34 | 35 | func TimedSumFunc(f SumFunc) SumFunc { 36 | return func(start int64, end int64) int64 { 37 | defer func(t time.Time) { 38 | fmt.Printf("-------Time Elapsed (%s): %v-------\n", getFuncName(f), time.Since(t)) 39 | }(time.Now()) 40 | 41 | return f(start, end) 42 | } 43 | } 44 | 45 | func SumFunc1(start, end int64) int64 { 46 | var sum int64 = 0 47 | if start > end { 48 | start, end = end, start 49 | } 50 | 51 | for i := start; i < end; i++ { 52 | sum += i 53 | } 54 | 55 | return sum 56 | } 57 | 58 | func SumFunc2(start, end int64) int64 { 59 | if start > end { 60 | start, end = end, start 61 | } 62 | 63 | return (end - start + 1) * (end + start) / 2 64 | } 65 | 66 | //一个http的例子 67 | func WithServerHeader(h http.HandlerFunc) http.HandlerFunc { 68 | return func(w http.ResponseWriter, r *http.Request) { 69 | log.Println("-------with server header-------") 70 | w.Header().Set("Server", "HelloServer v0.0.1") 71 | h(w, r) 72 | } 73 | } 74 | 75 | func WithAuthCookie(h http.HandlerFunc) http.HandlerFunc { 76 | return func(w http.ResponseWriter, r *http.Request) { 77 | log.Println("-------with auth cookie-------") 78 | cookie := http.Cookie{Name: "auth", Value: "pass", Path: "/"} 79 | http.SetCookie(w, &cookie) 80 | h(w, r) 81 | } 82 | } 83 | 84 | func WithBasicAuth(h http.HandlerFunc) http.HandlerFunc { 85 | return func(w http.ResponseWriter, r *http.Request) { 86 | log.Println("--------with basic auth---------") 87 | cookie, err := r.Cookie("auth") 88 | if cookie == nil || cookie.Value != "pass" || err != nil { 89 | w.WriteHeader(http.StatusForbidden) 90 | return 91 | } 92 | h(w, r) 93 | } 94 | } 95 | 96 | func WithDebugLog(h http.HandlerFunc) http.HandlerFunc { 97 | return func(w http.ResponseWriter, r *http.Request) { 98 | log.Println("--------with debug log---------") 99 | err := r.ParseForm() 100 | if err != nil { 101 | log.Println(err) 102 | return 103 | } 104 | 105 | log.Println(r.Form) 106 | log.Println("path = ", r.URL.Path) 107 | log.Println("scheme = ", r.URL.Scheme) 108 | h(w, r) 109 | } 110 | } 111 | 112 | func ServerHello(w http.ResponseWriter, r *http.Request) { 113 | log.Printf("received request %s from %s\n", r.URL.Path, r.RemoteAddr) 114 | fmt.Fprintln(w, "Hello World!" + r.URL.Path) 115 | } 116 | 117 | //上面的几个with修饰方法,不太优雅,可以进行下面的改造 118 | type HttpHandlerDecorator func(http.HandlerFunc) http.HandlerFunc 119 | 120 | func Handler(h http.HandlerFunc, decors ...HttpHandlerDecorator) http.HandlerFunc { 121 | for i := range decors { 122 | decorator := decors[len(decors)-1-i] 123 | h = decorator(h) 124 | } 125 | return h 126 | } 127 | 128 | //泛型的修饰器 129 | func Decorator(decoPtr, fn interface{}) (err error) { 130 | decoFunc := reflect.ValueOf(decoPtr).Elem() 131 | targetFunc := reflect.ValueOf(fn) 132 | 133 | v := reflect.MakeFunc(targetFunc.Type(), func(in []reflect.Value) (out []reflect.Value) { 134 | fmt.Println("before") 135 | out = targetFunc.Call(in) 136 | fmt.Println("after") 137 | return 138 | }) 139 | 140 | decoFunc.Set(v) 141 | return 142 | } 143 | 144 | func main() { 145 | h := decorator(Hello) 146 | h("Hello, I am roseduan") 147 | 148 | fn1 := TimedSumFunc(SumFunc1) 149 | res1 := fn1(1, 10000000) 150 | fmt.Println(res1) 151 | 152 | fn2 := TimedSumFunc(SumFunc2) 153 | res2 := fn2(1, 10000000) 154 | fmt.Println(res2) 155 | 156 | fmt.Println("----------运行HelloServer-----------") 157 | //http.HandleFunc("/v1/hello", WithServerHeader(ServerHello)) 158 | //http.HandleFunc("/v2/hello", WithAuthCookie(ServerHello)) 159 | //http.HandleFunc("/v3/hello", WithBasicAuth(ServerHello)) 160 | //http.HandleFunc("/v4/hello", WithDebugLog(ServerHello)) 161 | 162 | http.HandleFunc("/v1/hello", Handler(ServerHello, WithAuthCookie, WithServerHeader, WithBasicAuth)) 163 | 164 | err := http.ListenAndServe(":8080", nil) 165 | if err != nil { 166 | log.Fatal(err) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /error_handle.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "log" 9 | "os" 10 | ) 11 | 12 | //错误处理 13 | 14 | //Go语言中的资源清理主要使用 defer 关键字 15 | func Close(c io.Closer) { 16 | err := c.Close() 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | } 21 | 22 | // a bad case of error handle 23 | // func parse(r io.Reader) (*Point, error) { 24 | // 25 | // var p Point 26 | // 27 | // if err := binary.Read(r, binary.BigEndian, &p.Longitude); err != nil { 28 | // return nil, err 29 | // } 30 | // if err := binary.Read(r, binary.BigEndian, &p.Latitude); err != nil { 31 | // return nil, err 32 | // } 33 | // if err := binary.Read(r, binary.BigEndian, &p.Distance); err != nil { 34 | // return nil, err 35 | // } 36 | // if err := binary.Read(r, binary.BigEndian, &p.ElevationGain); err != nil { 37 | // return nil, err 38 | // } 39 | // if err := binary.Read(r, binary.BigEndian, &p.ElevationLoss); err != nil { 40 | // return nil, err 41 | // } 42 | // } 43 | 44 | //要处理上面这种 if err != nil 的代码,可以采用下面这种方式 45 | func Parse(r io.Reader, p *Point) (*Point, error) { 46 | var err error 47 | read := func(data interface{}) { 48 | err = binary.Read(r, binary.BigEndian, data) 49 | if err != nil { 50 | return 51 | } 52 | } 53 | 54 | read(p.Longitude) 55 | read(p.Latitude) 56 | read(p.Distance) 57 | read(p.ElevationGain) 58 | read(p.ElevationLoss) 59 | 60 | if err != nil { 61 | return nil, err 62 | } 63 | 64 | return p, nil 65 | } 66 | 67 | //还可以借鉴 bufio.NewScanner 进行改进 68 | type Reader struct { 69 | r io.Reader 70 | err error 71 | } 72 | 73 | func (r *Reader) read(data interface{}) { 74 | if r.err != nil { 75 | r.err = binary.Read(r.r, binary.BigEndian, data) 76 | } 77 | } 78 | 79 | func newParse(r io.Reader, p *Point) (*Point, error) { 80 | reader := Reader{r: r} 81 | reader.read(p.Longitude) 82 | reader.read(p.Latitude) 83 | reader.read(p.Distance) 84 | reader.read(p.ElevationGain) 85 | reader.read(p.ElevationLoss) 86 | 87 | if reader.err != nil { 88 | return nil, reader.err 89 | } 90 | 91 | return p, nil 92 | } 93 | 94 | type Point struct { 95 | Longitude []byte 96 | Latitude []byte 97 | Distance []byte 98 | ElevationGain []byte 99 | ElevationLoss []byte 100 | } 101 | 102 | //利用上面的这个技巧,再来看一个例子 103 | var b = []byte{114, 111, 115, 101, 100, 117, 97, 110, 23, 70} 104 | 105 | //这个byte数组的数据可以这样来构造 106 | // var buf bytes.Buffer 107 | // err := binary.Write(&buf, binary.BigEndian, []byte("roseduan")) 108 | // _ = binary.Write(&buf, binary.BigEndian, uint8(23)) 109 | // _ = binary.Write(&buf, binary.BigEndian, uint8(70)) 110 | // if err != nil { 111 | // log.Println(err) 112 | // } 113 | // 114 | // fmt.Println(buf.Bytes()) 115 | 116 | var r = bytes.NewReader(b) 117 | 118 | type MyPerson struct { 119 | Name [8]byte 120 | Age uint8 121 | Weight uint8 122 | err error 123 | } 124 | 125 | func (p *MyPerson) read(data interface{}) { 126 | if p.err == nil { 127 | p.err = binary.Read(r, binary.BigEndian, data) 128 | } 129 | } 130 | 131 | func (p *MyPerson) ReadName() *MyPerson { 132 | p.read(&p.Name) 133 | return p 134 | } 135 | 136 | func (p *MyPerson) ReadAge() *MyPerson { 137 | p.read(&p.Age) 138 | return p 139 | } 140 | 141 | func (p *MyPerson) ReadWeight() *MyPerson { 142 | p.read(&p.Weight) 143 | return p 144 | } 145 | 146 | func (p *MyPerson) PrintPersonInfo() { 147 | fmt.Printf("Name=%s, Age=%d, Weight=%d\n", p.Name, p.Age, p.Weight) 148 | } 149 | 150 | func main() { 151 | file, _ := os.OpenFile("/test/fileA", os.O_RDONLY, os.ModePerm) 152 | defer Close(file) 153 | //do something with the opened file 154 | 155 | fmt.Println("------------------") 156 | p := MyPerson{} 157 | p.ReadName().ReadAge().ReadWeight() 158 | 159 | if p.err != nil { 160 | log.Fatal(p.err) 161 | } 162 | 163 | p.PrintPersonInfo() 164 | } 165 | -------------------------------------------------------------------------------- /functional_options.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | //Functional Options 9 | 10 | type Server struct { 11 | Addr string 12 | Port int 13 | Protocol string 14 | Timeout time.Duration 15 | MaxConn int 16 | Tls *TlsConfig 17 | } 18 | 19 | type TlsConfig struct { 20 | Cert []byte 21 | PrivateKey []byte 22 | } 23 | 24 | //由于Go语言不支持函数重载,所以需要写不同的方法来满足不同的需求 25 | func NewDefaultServer(addr string, port int) *Server { 26 | return &Server{addr, port, "tcp", 10 * time.Second, 10, nil} 27 | } 28 | 29 | func NewTlsServer(addr string, port int, cfg *TlsConfig) *Server { 30 | return &Server{addr, port, "tcp", 10 * time.Second, 10, cfg} 31 | } 32 | 33 | func NewServerWithTimeout(addr string, port int, timeout time.Duration) *Server { 34 | return &Server{addr, port, "tcp", timeout, 100, nil} 35 | } 36 | 37 | //要想解决这种代码冗余的问题,一种常见的方式是使用配置对象 38 | 39 | //将可更改的配置属性放到一个结构体中 40 | type ServerConfig struct { 41 | Protocol string 42 | Timeout time.Duration 43 | MaxConn int 44 | Tls TlsConfig 45 | } 46 | 47 | //然后server结构体和创建server的方法就可以这样写了 48 | //type Server struct { 49 | // Addr string 50 | // Port int 51 | // cfg *ServerConfig 52 | //} 53 | // 54 | //func NewServer(addr string, port int, cfg ServerConfig) *Server { 55 | // return &Server{addr, port, cfg} 56 | //} 57 | 58 | //另一种解决方式:使用builder模式 59 | type ServerBuilder struct { 60 | Server 61 | } 62 | 63 | func (sb *ServerBuilder) New(addr string, port int) *ServerBuilder { 64 | sb.Server.Addr = addr 65 | sb.Server.Port = port 66 | return sb 67 | } 68 | 69 | func (sb *ServerBuilder) Protocol(p string) *ServerBuilder { 70 | sb.Server.Protocol = p 71 | return sb 72 | } 73 | 74 | func (sb *ServerBuilder) Timeout(timeout time.Duration) *ServerBuilder { 75 | sb.Server.Timeout = timeout 76 | return sb 77 | } 78 | 79 | func (sb *ServerBuilder) MaxConn(maxConn int) *ServerBuilder { 80 | sb.Server.MaxConn = maxConn 81 | return sb 82 | } 83 | 84 | func (sb *ServerBuilder) Tls(cfg *TlsConfig) *ServerBuilder { 85 | sb.Server.Tls = cfg 86 | return sb 87 | } 88 | 89 | func (sb *ServerBuilder) Build() Server { 90 | return sb.Server 91 | } 92 | 93 | //builder模式的使用示例 94 | // builder := ServerBuilder{} 95 | // s := builder.New("https://roseduan.com", 80).Protocol("http").Timeout(5 * time.Second).Build() 96 | // fmt.Println(s) 97 | 98 | //一种更加优雅的处理方式:functional options 99 | 100 | type Option func(*Server) 101 | 102 | func Protocol(p string) Option { 103 | return func(server *Server) { 104 | server.Protocol = p 105 | } 106 | } 107 | 108 | func Timeout(timeout time.Duration) Option { 109 | return func(server *Server) { 110 | server.Timeout = timeout 111 | } 112 | } 113 | 114 | func MaxConn(maxConn int) Option { 115 | return func(server *Server) { 116 | server.MaxConn = maxConn 117 | } 118 | } 119 | 120 | func Tls(tls *TlsConfig) Option { 121 | return func(server *Server) { 122 | server.Tls = tls 123 | } 124 | } 125 | 126 | //构造方法可以这样写了 127 | func NewServer(addr string, port int, options ...Option) *Server { 128 | server := &Server{Addr: addr, Port: port} 129 | for _, opt := range options { 130 | opt(server) 131 | } 132 | 133 | return server 134 | } 135 | 136 | func main() { 137 | server := NewDefaultServer("https://roseduan.com", 80) 138 | fmt.Println(server) 139 | 140 | builder := ServerBuilder{} 141 | s := builder.New("https://roseduan.com", 80).Protocol("http").Timeout(5 * time.Second).Build() 142 | fmt.Println(s) 143 | 144 | s1 := NewServer("https://roseduan.com", 80) 145 | s2 := NewServer("https://roseduan.com", 80, Protocol("http")) 146 | s3 := NewServer("https://roseduan.com", 80, Timeout(5 * time.Second), MaxConn(10)) 147 | fmt.Printf("%+v\n", s1) 148 | fmt.Printf("%+v\n", s2) 149 | fmt.Printf("%+v\n", s3) 150 | } 151 | -------------------------------------------------------------------------------- /generation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "reflect" 8 | ) 9 | 10 | //Go Generation 11 | 12 | //一个简单的容器,支持任意数据类型 13 | type Container []interface{} 14 | 15 | func (c *Container) Put(val interface{}) { 16 | *c = append(*c, val) 17 | } 18 | 19 | func (c *Container) Get() interface{} { 20 | res := (*c)[0] 21 | *c = (*c)[1:] 22 | return res 23 | } 24 | 25 | //使用反射进行自动类型转换的Container 26 | type MyContainer struct { 27 | s reflect.Value 28 | } 29 | 30 | func NewContainer(t reflect.Type, size int) *MyContainer { 31 | if size <= 0 { 32 | size = 64 33 | } 34 | 35 | return &MyContainer{ 36 | s: reflect.MakeSlice(reflect.SliceOf(t), 0, size), 37 | } 38 | } 39 | 40 | func (c *MyContainer) MyPut(val interface{}) error { 41 | //类型检查 42 | if reflect.ValueOf(val).Type() != c.s.Type().Elem() { 43 | return errors.New(fmt.Sprintf("Put: can`t put a %T into a slice of %s", 44 | val, c.s.Type().Elem())) 45 | } 46 | 47 | c.s = reflect.Append(c.s, reflect.ValueOf(val)) 48 | return nil 49 | } 50 | 51 | func (c *MyContainer) MyGet(res interface{}) error { 52 | v := reflect.ValueOf(res) 53 | if v.Kind() != reflect.Ptr || v.Elem().Type() != c.s.Type().Elem() { 54 | return errors.New(fmt.Sprintf("Get: needs *%s but got %T", c.s.Type().Elem(), v)) 55 | } 56 | 57 | v.Elem().Set(c.s.Index(0)) 58 | c.s = c.s.Slice(1, c.s.Len()) 59 | return nil 60 | } 61 | 62 | func main() { 63 | //Container容器的使用 64 | fmt.Println("------------Container容器的使用------------") 65 | c := &Container{} 66 | c.Put(1) 67 | c.Put("roseduan") 68 | c.Put("good") 69 | c.Put(1.4542) 70 | 71 | fmt.Printf("%+v\n", c.Get()) 72 | fmt.Printf("%+v\n", c.Get()) 73 | fmt.Printf("%+v\n", c.Get()) 74 | 75 | //取出数据之后,需要进行数据类型的转换 76 | e, ok := c.Get().(float64) 77 | if !ok { 78 | log.Println("the value is not float64") 79 | } else { 80 | fmt.Println(e) 81 | } 82 | 83 | fmt.Println("------------My Container容器的使用------------") 84 | container := NewContainer(reflect.TypeOf(1), 16) 85 | err := container.MyPut(112) 86 | if err != nil { 87 | log.Println(err) 88 | } 89 | 90 | _ = container.MyPut(1122) 91 | _ = container.MyPut(23200) 92 | 93 | var r1 int 94 | if err := container.MyGet(&r1); err != nil { 95 | log.Println(err) 96 | } 97 | 98 | fmt.Println("r1 = ", r1) 99 | 100 | var r2 int 101 | _ = container.MyGet(&r2) 102 | fmt.Println("r2 = ", r2) 103 | } 104 | -------------------------------------------------------------------------------- /ioc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //委托和控制反转 6 | 7 | 8 | //Go语言中的结构体可以嵌入 9 | type Widget struct { 10 | X, Y int 11 | } 12 | 13 | type Label struct { 14 | Widget 15 | Text string 16 | } 17 | 18 | type Button struct { 19 | Label 20 | } 21 | 22 | type ListBox struct { 23 | Widget 24 | Texts []string 25 | Index int 26 | } 27 | 28 | //方法重写 29 | type Painter interface { 30 | Paint() 31 | } 32 | 33 | type Clicker interface { 34 | Click() 35 | } 36 | 37 | func (l *Label) Paint() { 38 | fmt.Printf("Label.Paint(%q)\n", l.Text) 39 | } 40 | 41 | func (b *Button) Paint() { 42 | fmt.Printf("Button.Paint(%q)\n", b.Text) 43 | } 44 | 45 | func (lis *ListBox) Paint() { 46 | fmt.Printf("ListBox.Paint(%q)\n", lis.Texts) 47 | } 48 | 49 | func (b *Button) Click() { 50 | fmt.Printf("Button.Click(%q)\n", b.Text) 51 | } 52 | 53 | func (lis *ListBox) Click() { 54 | fmt.Printf("ListBox.Click(%q)\n", lis.Texts) 55 | } 56 | 57 | //控制反转的例子 58 | 59 | //定义一个简单的Set 60 | type IntSet struct { 61 | data map[int]bool 62 | } 63 | 64 | func NewIntSet() IntSet { 65 | return IntSet{make(map[int]bool)} 66 | } 67 | 68 | func (i *IntSet) Add(x int) { 69 | i.data[x] = true 70 | } 71 | 72 | func (i *IntSet) Delete(x int) { 73 | delete(i.data, x) 74 | } 75 | 76 | func (i *IntSet) Contains(x int) bool { 77 | return i.data[x] 78 | } 79 | 80 | //实现一个有Undo功能的IntSet 81 | type UndoableIntSet struct { 82 | IntSet 83 | fn []func() 84 | } 85 | 86 | func NewUndoableIntSet() *UndoableIntSet { 87 | return &UndoableIntSet{NewIntSet(), nil} 88 | } 89 | 90 | func (u *UndoableIntSet) Add(x int) { 91 | if !u.Contains(x) { 92 | u.IntSet.data[x] = true 93 | u.fn = append(u.fn, func() { 94 | u.Delete(x) 95 | }) 96 | } else { 97 | u.fn = append(u.fn, nil) 98 | } 99 | } 100 | 101 | func (u *UndoableIntSet) Delete(x int) { 102 | if u.Contains(x) { 103 | delete(u.IntSet.data, x) 104 | u.fn = append(u.fn, func() { 105 | u.Add(x) 106 | }) 107 | } else { 108 | u.fn = append(u.fn, nil) 109 | } 110 | } 111 | 112 | func (u *UndoableIntSet) Undo() bool { 113 | if len(u.fn) == 0 { 114 | return false 115 | } 116 | 117 | idx := len(u.fn)-1 118 | if u.fn[idx] != nil { 119 | u.fn[idx]() 120 | u.fn[idx] = nil 121 | } 122 | 123 | u.fn = u.fn[:idx] 124 | return true 125 | } 126 | 127 | //依赖反转 128 | type Undo []func() 129 | 130 | func (u *Undo) Add(fn func()) { 131 | *u = append(*u, fn) 132 | } 133 | 134 | func (u *Undo) Execute() bool { 135 | if len(*u) == 0 { 136 | return false 137 | } 138 | 139 | idx := len(*u)-1 140 | if fn := (*u)[idx]; fn != nil { 141 | fn() 142 | (*u)[idx] = nil 143 | } 144 | 145 | *u = (*u)[:idx] 146 | return true 147 | } 148 | 149 | type StringSet struct { 150 | data map[string]bool 151 | undo Undo 152 | } 153 | 154 | func NewStringSet() *StringSet { 155 | return &StringSet{data: make(map[string]bool)} 156 | } 157 | 158 | func (s *StringSet) Add(x string) { 159 | if !s.Contains(x) { 160 | s.data[x] = true 161 | s.undo.Add(func() { 162 | s.Delete(x) 163 | }) 164 | } else { 165 | s.undo.Add(nil) 166 | } 167 | } 168 | 169 | func (s *StringSet) Delete(x string) { 170 | if s.Contains(x) { 171 | delete(s.data, x) 172 | s.undo.Add(func() { 173 | s.Add(x) 174 | }) 175 | } else { 176 | s.undo.Add(nil) 177 | } 178 | } 179 | 180 | func (s *StringSet) Contains(x string) bool { 181 | return s.data[x] 182 | } 183 | 184 | func main() { 185 | label := Label{Widget{10, 20}, "a label"} 186 | button1 := Button{Label{Widget{10, 70}, "OK"}} 187 | button2 := Button{Label{Widget{10, 20}, "Cancel"}} 188 | listBox := ListBox{Widget{10, 40}, []string{"AL", "AK", "AZ", "AR"}, 0} 189 | 190 | for _, painter := range []Painter{&label, &listBox, &button1, &button2} { 191 | painter.Paint() 192 | } 193 | 194 | for _, widget := range []interface{}{&label, &listBox, &button1, &button2} { 195 | widget.(Painter).Paint() 196 | if clicker, ok := widget.(Clicker); ok { 197 | clicker.Click() 198 | } 199 | fmt.Println() // print a empty line 200 | } 201 | 202 | fmt.Println("-----------使用UndoableIntSet-----------") 203 | set := NewUndoableIntSet() 204 | set.Add(1) 205 | set.Add(4) 206 | set.Add(3) 207 | 208 | set.Undo() 209 | fmt.Println(set.data) 210 | 211 | set.Undo() 212 | fmt.Println(set.data) 213 | 214 | set.Undo() 215 | fmt.Println(set.data) 216 | 217 | fmt.Println("-----------使用StringSet-----------") 218 | s := NewStringSet() 219 | s.Add("a") 220 | s.Add("b") 221 | s.Add("c") 222 | 223 | fmt.Println(s.data) 224 | s.undo.Execute() 225 | s.undo.Execute() 226 | fmt.Println(s.data) 227 | } 228 | -------------------------------------------------------------------------------- /map_reduce.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | //函数式操作 map reduce filter 12 | 13 | func MapStrToStr(arr []string, fn func(s string) string) []string { 14 | var newArr []string 15 | for _, v := range arr { 16 | newArr = append(newArr, fn(v)) 17 | } 18 | 19 | return newArr 20 | } 21 | 22 | func MapStrToInt(arr []string, fn func(s string) int) []int { 23 | var res []int 24 | for _, v := range arr { 25 | res = append(res, fn(v)) 26 | } 27 | 28 | return res 29 | } 30 | 31 | //reduce函数示例 32 | func Reduce(arr []string, fn func(s string) int) int { 33 | sum := 0 34 | for _, v := range arr { 35 | sum += fn(v) 36 | } 37 | 38 | return sum 39 | } 40 | 41 | //filter函数示例 42 | func Filter(arr []string, fn func(s string) bool) []string { 43 | var newArr []string 44 | for _, v := range arr { 45 | if fn(v) { 46 | newArr = append(newArr, v) 47 | } 48 | } 49 | 50 | return newArr 51 | } 52 | 53 | //业务示例 54 | type Employee struct { 55 | Name string 56 | Age int 57 | Vacation int 58 | Salary float32 59 | } 60 | 61 | var list = []Employee{ 62 | {"Hao", 44, 4, 8000}, 63 | {"Bob", 34, 10, 5000}, 64 | {"Alice", 23, 5, 9000}, 65 | {"Jack", 26, 3, 4000}, 66 | {"Tom", 48, 9, 7500}, 67 | {"Marry", 29, 7, 6000}, 68 | {"Mike", 32, 8, 4000}, 69 | } 70 | 71 | func EmployeeCountIf(list []Employee, fn func(e *Employee) bool) (count int) { 72 | for _, v := range list { 73 | if fn(&v) { 74 | count++ 75 | } 76 | } 77 | return 78 | } 79 | 80 | func EmployeeFilterIn(list []Employee, fn func(e *Employee) bool) []Employee { 81 | var res []Employee 82 | for _, v := range list { 83 | if fn(&v) { 84 | res = append(res, v) 85 | } 86 | } 87 | 88 | return res 89 | } 90 | 91 | func EmployeeSumIf(list []Employee, fn func(e *Employee) int) int { 92 | sum := 0 93 | for _, v := range list { 94 | sum += fn(&v) 95 | } 96 | 97 | return sum 98 | } 99 | 100 | //泛型的map 101 | func Map(data ,fn interface{}) []interface{} { 102 | vdata := reflect.ValueOf(data) 103 | vfn := reflect.ValueOf(fn) 104 | 105 | result := make([]interface{}, vdata.Len()) 106 | for i := 0; i < vdata.Len(); i++ { 107 | result[i] = vfn.Call([]reflect.Value{vdata.Index(i)})[0].Interface() 108 | } 109 | 110 | return result 111 | } 112 | 113 | //上面的这个Map的问题是没有进行类型检查,所以这里可以手动进行检查 114 | 115 | func Transform(slice, function interface{}) (interface{}, error) { 116 | return transform(slice, function, false) 117 | } 118 | 119 | func TransformInPlace(slice, function interface{}) (interface{}, error) { 120 | return transform(slice, function, true) 121 | } 122 | 123 | func transform(slice, function interface{}, inplace bool) (interface{}, error) { 124 | sliceType := reflect.ValueOf(slice) 125 | if sliceType.Kind() != reflect.Slice { 126 | return nil, errors.New("not slice type") 127 | } 128 | 129 | vfn := reflect.ValueOf(function) 130 | elemType := sliceType.Type().Elem() 131 | if !verifySignature(vfn, elemType, nil) { 132 | return nil, errors.New("func is not the right type") 133 | } 134 | 135 | sliceOutType := sliceType 136 | if !inplace { 137 | sliceOutType = reflect.MakeSlice(reflect.SliceOf(vfn.Type().Out(0)), sliceType.Len(), sliceType.Len()) 138 | } 139 | 140 | for i := 0; i < sliceType.Len(); i++ { 141 | sliceOutType.Index(i).Set(vfn.Call([]reflect.Value{sliceType.Index(i)})[0]) 142 | } 143 | 144 | return sliceOutType.Interface(), nil 145 | } 146 | 147 | func verifySignature(fn reflect.Value, types ...reflect.Type) bool { 148 | if fn.Kind() != reflect.Func { 149 | return false 150 | } 151 | 152 | //检查方法入参和出参是否符合预期 153 | if fn.Type().NumIn() != len(types)-1 || fn.Type().NumOut() != 1 { 154 | return false 155 | } 156 | 157 | for i := 0; i < len(types)-1; i++ { 158 | if fn.Type().In(i) != types[i] { 159 | return false 160 | } 161 | } 162 | 163 | outType := types[len(types)-1] 164 | if outType != nil && fn.Type().Out(0) != outType { 165 | return false 166 | } 167 | 168 | return true 169 | } 170 | 171 | //利用上面的技巧,将reduce和filter函数都改造成泛型的 172 | func GenericReduce(slice, pairFunc, zero interface{}) (interface{}, error) { 173 | sliceInType := reflect.ValueOf(slice) 174 | if sliceInType.Kind() != reflect.Slice { 175 | return nil, errors.New("not slice type") 176 | } 177 | 178 | length := sliceInType.Len() 179 | if length == 0 { 180 | return zero, nil 181 | } else if length == 1 { 182 | return sliceInType.Index(0), nil 183 | } 184 | 185 | elemType := sliceInType.Type().Elem() 186 | vfn := reflect.ValueOf(pairFunc) 187 | if !verifySignature(vfn, elemType, elemType, elemType) { 188 | return nil, errors.New("func is not the right type") 189 | } 190 | 191 | ins := [2]reflect.Value{sliceInType.Index(0), sliceInType.Index(1)} 192 | out := vfn.Call(ins[:])[0] 193 | 194 | for i := 2; i < length; i++ { 195 | ins[0], ins[1] = out, sliceInType.Index(i) 196 | out = vfn.Call(ins[:])[0] 197 | } 198 | 199 | return out.Interface(), nil 200 | } 201 | 202 | 203 | func GenericFilter(slice, function interface{}) interface{} { 204 | result, _ := filter(slice, function, false) 205 | return result 206 | } 207 | 208 | func GenericFilterInPlace(slicePtr, function interface{}) { 209 | in := reflect.ValueOf(slicePtr) 210 | if in.Kind() != reflect.Ptr { 211 | panic("FilterInPlace: wrong type, " + 212 | "not a pointer to slice") 213 | } 214 | _, n := filter(in.Elem().Interface(), function, true) 215 | in.Elem().SetLen(n) 216 | } 217 | 218 | var boolType = reflect.ValueOf(true).Type() 219 | 220 | func filter(slice, function interface{}, inPlace bool) (interface{}, int) { 221 | 222 | sliceInType := reflect.ValueOf(slice) 223 | if sliceInType.Kind() != reflect.Slice { 224 | panic("filter: wrong type, not a slice") 225 | } 226 | 227 | fn := reflect.ValueOf(function) 228 | elemType := sliceInType.Type().Elem() 229 | if !verifySignature(fn, elemType, boolType) { 230 | panic("filter: function must be of type func(" + elemType.String() + ") bool") 231 | } 232 | 233 | var which []int 234 | for i := 0; i < sliceInType.Len(); i++ { 235 | if fn.Call([]reflect.Value{sliceInType.Index(i)})[0].Bool() { 236 | which = append(which, i) 237 | } 238 | } 239 | 240 | out := sliceInType 241 | 242 | if !inPlace { 243 | out = reflect.MakeSlice(sliceInType.Type(), len(which), len(which)) 244 | } 245 | for i := range which { 246 | out.Index(i).Set(sliceInType.Index(which[i])) 247 | } 248 | 249 | return out.Interface(), len(which) 250 | } 251 | 252 | func main() { 253 | fmt.Println("------------使用MapStrToStr------------") 254 | arr := []string{"roseduan", "jack zhang", "golang", "24"} 255 | arr = MapStrToStr(arr, strings.ToUpper) 256 | fmt.Println(arr) 257 | 258 | fmt.Println("------------使用MapStrToInt------------") 259 | res := MapStrToInt(arr, func(s string) int { 260 | return len(s) 261 | }) 262 | fmt.Println(res) 263 | 264 | //逻辑自定义,例如计算字符串长度之和 265 | arr2 := []string{"CHN Beijing", "USA New York", "UK London", "CHN Shanghai"} 266 | sum := Reduce(arr2, func(s string) int { 267 | return len(s) 268 | }) 269 | fmt.Println(sum) 270 | 271 | c := Filter(arr2, func(s string) bool { 272 | return strings.HasPrefix(s, "CHN") 273 | }) 274 | fmt.Println(c) 275 | 276 | fmt.Println("------------EmployeeCountIf------------") 277 | count := EmployeeCountIf(list, func(e *Employee) bool { 278 | return e.Salary > 5000 279 | }) 280 | fmt.Println("salary more than 5000 : ", count) 281 | 282 | fmt.Println("------------EmployeeFilterIn------------") 283 | v := EmployeeFilterIn(list, func(e *Employee) bool { 284 | return e.Vacation > 5 && e.Vacation < 10 285 | }) 286 | fmt.Println(v) 287 | 288 | fmt.Println("------------EmployeeSumIf------------") 289 | sum = EmployeeSumIf(list, func(e *Employee) int { 290 | return e.Age 291 | }) 292 | fmt.Println(sum) 293 | 294 | fmt.Println("------------使用简单的泛型Map------------") 295 | 296 | //整数数组 297 | arr3 := []int{1, 2, 3, 4} 298 | res2 := Map(arr3, func(x int) int { 299 | return x * x 300 | }) 301 | fmt.Println(res2) 302 | 303 | //字符串数组 304 | arr4 := []string{"Java", "Golang", "Python", "Rust"} 305 | res4 := Map(arr4, strings.ToUpper) 306 | fmt.Println(res4) 307 | 308 | fmt.Println("------------使用健壮版的泛型Map------------") 309 | 310 | //用于字符串数组 311 | list := []string{"1", "2", "3", "4", "5"} 312 | res5, err := Transform(list, func(s string) string { 313 | return s + s + s 314 | }) 315 | if err != nil { 316 | log.Fatal(err) 317 | } 318 | 319 | fmt.Println(res5) 320 | 321 | //用于整型数组 322 | nums := []int{1, 2, 3, 4, 5} 323 | aa, _ := TransformInPlace(nums, func(n int) int { 324 | return n * 3 325 | }) 326 | fmt.Println(nums) 327 | fmt.Println(aa) 328 | 329 | //用于结构体 330 | var employeeList = []Employee{ 331 | {"Hao", 44, 4, 8000}, 332 | {"Bob", 34, 10, 5000}, 333 | {"Alice", 23, 5, 9000}, 334 | {"Jack", 26, 3, 4000}, 335 | } 336 | 337 | lis, _ := Transform(employeeList, func(e Employee) Employee { 338 | e.Salary += 1000 339 | e.Vacation += 1 340 | return e 341 | }) 342 | fmt.Printf("%+v\n", lis) 343 | } 344 | -------------------------------------------------------------------------------- /pipeline.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | //Pipeline 模式 6 | 7 | //一个简单的示例 8 | func echo(nums []int) <-chan int { 9 | out := make(chan int) 10 | go func() { 11 | for _, n := range nums { 12 | out <- n 13 | } 14 | close(out) 15 | }() 16 | 17 | return out 18 | } 19 | 20 | //平方函数 21 | func square(in <-chan int) <-chan int { 22 | out := make(chan int) 23 | go func() { 24 | for n := range in { 25 | out <- n * n 26 | } 27 | close(out) 28 | }() 29 | 30 | return out 31 | } 32 | 33 | //过滤奇数函数 34 | func odd(in <-chan int) <-chan int { 35 | out := make(chan int) 36 | go func() { 37 | for n := range in { 38 | if n % 2 == 1 { 39 | out <- n * n 40 | } 41 | } 42 | close(out) 43 | }() 44 | 45 | return out 46 | } 47 | 48 | //求和函数 49 | func sum(in <-chan int) <-chan int { 50 | out := make(chan int) 51 | go func() { 52 | sum := 0 53 | for n := range in { 54 | sum += n 55 | } 56 | out <- sum 57 | close(out) 58 | }() 59 | return out 60 | } 61 | 62 | //func EchoFunc(in <-chan int, fn func(in <- chan int, out chan int)) <-chan int { 63 | // out := make(chan int) 64 | // go fn(in, out) 65 | // return out 66 | //} 67 | 68 | //上面几个函数的多层嵌套使用,可以使用一个代理函数解决 69 | type EchoFunc func([]int) <- chan int 70 | type PipeFunc func(in <-chan int) <-chan int 71 | 72 | func pipeline(nums []int, echoFunc EchoFunc, pipeFunc ...PipeFunc) <-chan int { 73 | ch := echoFunc(nums) 74 | for i := range pipeFunc { 75 | ch = pipeFunc[i](ch) 76 | } 77 | return ch 78 | } 79 | 80 | func main() { 81 | ////简单的pipeline的使用方式 82 | nums := []int{1, 2, 3, 4, 5, 6, 7} 83 | for n := range square(echo(nums)) { 84 | fmt.Println(n) 85 | } 86 | 87 | //另一种更简洁的方式 88 | for n := range pipeline(nums, echo, square, odd, sum) { 89 | fmt.Println(n) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /visitor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "encoding/xml" 6 | "fmt" 7 | "log" 8 | ) 9 | 10 | //Visitor模式 11 | 12 | //一个简单的visitor 13 | type Visitor func(shape Shape) 14 | 15 | type Shape interface { 16 | accept(v Visitor) 17 | } 18 | 19 | type Circle struct { 20 | Radius int 21 | } 22 | 23 | type Rectangle struct { 24 | Width, Height int 25 | } 26 | 27 | func (c Circle) accept(v Visitor) { 28 | v(c) 29 | } 30 | 31 | func (r Rectangle) accept(v Visitor) { 32 | v(r) 33 | } 34 | 35 | func JsonVisitor(shape Shape) { 36 | res, err := json.Marshal(shape) 37 | if err != nil { 38 | log.Fatal(err) 39 | } 40 | 41 | fmt.Println(string(res)) 42 | } 43 | 44 | func XmlVisitor(shape Shape) { 45 | res, err := xml.Marshal(shape) 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | 50 | fmt.Println(string(res)) 51 | } 52 | 53 | //kubectl的实现方法 54 | 55 | type VisitorFunc func(*Info, error) error 56 | 57 | type InfoVisitor interface { 58 | Visit(VisitorFunc) error 59 | } 60 | 61 | type Info struct { 62 | Namespace string 63 | Name string 64 | OtherThings string 65 | } 66 | 67 | func (info *Info) Visit(fn VisitorFunc) error { 68 | return fn(info, nil) 69 | } 70 | 71 | type NameVisitor struct { 72 | visitor InfoVisitor 73 | } 74 | 75 | func (v NameVisitor) Visit(fn VisitorFunc) error { 76 | return v.visitor.Visit(func(info *Info, err error) error { 77 | fmt.Println("NameVisitor before call function") 78 | err = fn(info, err) 79 | if err == nil { 80 | fmt.Printf("Name=%s, Namespace=%s\n", info.Name, info.Namespace) 81 | } 82 | fmt.Println("NameVisitor after call function") 83 | return err 84 | }) 85 | } 86 | 87 | type OtherVisitor struct { 88 | visitor InfoVisitor 89 | } 90 | 91 | func (v OtherVisitor) Visit(fn VisitorFunc) error { 92 | return v.visitor.Visit(func(info *Info, err error) error { 93 | fmt.Println("OtherVisitor before call function") 94 | err = fn(info, err) 95 | if err == nil { 96 | fmt.Printf("OtherThings=%s\n", info.OtherThings) 97 | } 98 | fmt.Println("OtherVisitor after call function") 99 | return err 100 | }) 101 | } 102 | 103 | type LogVisitor struct { 104 | visitor InfoVisitor 105 | } 106 | 107 | func (v LogVisitor) Visit(fn VisitorFunc) error { 108 | return v.visitor.Visit(func(info *Info, err error) error { 109 | fmt.Println("LogVisitor before call function") 110 | err = fn(info, err) 111 | fmt.Println("LogVisitor after call function") 112 | return err 113 | }) 114 | } 115 | 116 | func main() { 117 | c := Circle{10} 118 | r := Rectangle{10, 20} 119 | shapes := []Shape{c, r} 120 | 121 | for _, s := range shapes { 122 | s.accept(JsonVisitor) 123 | s.accept(XmlVisitor) 124 | } 125 | 126 | info := Info{} 127 | var v InfoVisitor = &info 128 | v = LogVisitor{v} 129 | v = NameVisitor{v} 130 | v = OtherVisitor{v} 131 | 132 | loadFile := func(info *Info, err error) error { 133 | info.Name = "roseduan" 134 | info.Namespace = "roseduan.com" 135 | info.OtherThings = "I am a nice person" 136 | return nil 137 | } 138 | 139 | v.Visit(loadFile) 140 | } 141 | --------------------------------------------------------------------------------