GopherChina 2020 Go Programming Patterns 学习笔记篇2

本篇继续学习左耳朵耗子老师的Go Programming Patterns下半部分,PPT太长了,70多页。

Topic 10 函数化的选项配置

由于Golang不允许使用同一个名字来命名函数,必须是不同的名称,即使参数不同,这与Java不一样,java的方法签名是包含参数的。所以遇到那种多个参数来实例化一个变量的,就会比较麻烦。会有类似代码产生:

type Server struct {
	Addr string
	Port int
	Protocol string 
	Timeout time.Duration
	MaxConns int
	TLS *tls.Config 
}

func NewServer(addr string, port int) (*Server, error) {
//...
}
func NewTLSServer(addr string, port int, tls *tls.Config) (*Server, error) {
//...
}
func NewServerWithTimeout(addr string, port int, timeout time.Duration) (*Server, error) { //...
}
 
func NewTLSServerWithMaxConnAndTimeout(addr string, port int, maxconns int, timeout time.Duration, tls *tls.Config) (*Server, error) {
//...
}

然后就有一种,使用专用配置结构体来优化这种实例化函数。

type Config struct { Protocol string
	Timeout time.Duration
	Maxconns int
	TLS *tls.Config
}

type Server struct {
	Addr string
	Port int
	Conf *Config
}

func NewServer(addr string, port int, conf *Config) (*Server, error) {
	//...
}

//Using the default configuratrion
srv1, _ := NewServer("localhost", 9000, nil)

conf := ServerConfig{Protocol:"tcp", Timeout: 60*time.Duration} 
srv2, _ := NewServer("locahost", 9000, &conf)
}

这样写有什么问题,这样有一个问题是零值或者nil值的处理,即在NewServer里需要处理这些零值,比如MaxConn要处理是否为0,TLS是否为nil,需要挨个判断,然后处理。然后就有了这种函数化参数的令人眼前一亮的操作。

type Option func(*Server)
func Protocol(p string) Option {
    return func(s *Server) {
        s.Protocol = p
    }
}
func Timeout(timeout time.Duration) Option {
	return func(s *Server) {
        s.Timeout = timeout
    }
}
func MaxConns(maxconns int) Option {
    return func(s *Server) {
        s.MaxConns = maxconns
    }
}
func TLS(tls *tls.Config) Option {
    return func(s *Server) {
		s.TLS = tls 
	}
}


func NewServer(addr string, port int, options ...func(*Server)) (*Server, error) {
   srv := Server{
        Addr:
        Port:
        Protocol: "tcp",
        Timeout:  30 * time.Second,
        MaxConns: 1000,
        TLS:      nil,
    }
    for _, option := range options {
        option(&srv)
    }
	//...
    return &srv, nil
}

// 使用
s1, _ := NewServer("localhost", 1024)
s2, _ := NewServer("localhost", 2048, Protocol("udp"))
s3, _ := NewServer("0.0.0.0", 8080, Timeout(300*time.Second), MaxConns(1000))

乍一看,有点懵逼是吧。就是把所有的参数,使用了函数来处理,并且返回的是个函数,他通过把参数传递给了要返回的函数。要返回的函数干了啥呢?它把传入的参数,设置到Server这个要初始化的实例上,这样就可以达到在初始化中直接挨个执行这些func,传入sever实例,即可完成初始化。只是我觉得这样做,不如直接给Server写参数函数,直接设置参数值不就好了吗?令人疑惑

 	func(s *Server) {
        s.Timeout = timeout
    }

Topic 11 Map/Reduce/Filter.

高阶函数

上一篇:From Python to Java


下一篇:Panasonic Programming Contest 2020 C (Sqrt Inequality) 题解