- GoLang构造函数
- 构造函数源码
- 代码案例1
- 代理案例2
- 流程解读
- 构造函数源码
GoLang构造函数
具体代码位置 构造函数 我之前的的另一个学习项目
另一篇笔记 Golang学习笔记 中的构造函数和复合声明部分也有描述和简单的实例
写这个笔记的原因,是因为前一阵子过同事的goLang代码, 看到他写的构造函数深感无奈.所以在这里记一下,我之前的案例.
构造函数源码
代码案例1
package taskrunner //runner对象 type Runner struct { Controller controlChan //Dispatcher和Executor的生产者和消费者互相交互信息 Error controlChan //告知程序是否关闭资源 Data dataChan //真正的交互数据 dataSize int //传输的数据大小 longLived bool //是否是长期存在的资源(不回执行close()回收资源) Dispatcher fn //分配器(生产者) Executor fn //执行者(消费者) } //创建启动任务,模拟构造函数 func NewRunner(size int, longLived bool, d fn, e fn) *Runner { return &Runner{ Controller: make(chan string, 1), //要带buffer Error: make(chan string, 1), Data: make(chan interface{}, size), longLived: longLived, dataSize: size, Dispatcher: d, Executor: e, } } //开始分配任务(常驻任务),长时间等待Controller channel和Data channel的数据来做处理 func (r *Runner) startDispatch() { //声明匿名函数 defer func() { //判断是否是要常驻内存,不需要的话就关闭所有channel if !r.longLived { close(r.Controller) close(r.Data) close(r.Error) } }() //没有这里的()该函数不会自动执行 //死循环不断处理消费者和生产者的channel中的数据 for { select { //读取Controller的channel中的数据,判断是生产者还是消费者 case c := <-r.Controller: //生产者 if c == READY_TO_DISPATCH { //把传入的数据,放入到生产者的回调函数中,同时判断回调函数的处理结果 err := r.Dispatcher(r.Data) if err != nil { //回调函数执行出错,通过传参, 指定关闭 r.Error <- CLOSE } else { //通过传参,切换为消费者 r.Controller <- READY_TO_EXECUTE } } //消费者 if c == READY_TO_EXECUTE { //把传入的数据,放入到消费者的回调函数中,同时判断回调函数的处理结果 err := r.Executor(r.Data) if err != nil { //回调函数执行出错,通过传参,指定关闭 r.Error <- CLOSE } else { //通过传参,切换为生产者 r.Controller <- READY_TO_DISPATCH } } //读取channel中需要关闭的资源 case e := <-r.Error: if e == CLOSE { return } default: } } } //启动生产者和消费者模型 func (r *Runner) StartAll() { //开启生产者和消费者模型,同时预制状态,否则进程会僵死 r.Controller <- READY_TO_DISPATCH //启动生产者 r.startDispatch() }
代理案例2
package taskrunner import "time" type Worker struct { /** *ticker只要定义完成,从此刻开始计时,不需要任何其他的操作,每隔固定时间都会触发。 *timer定时器,是到固定时间后会执行一次 *如果timer定时器要每隔间隔的时间执行,实现ticker的效果,使用 func (t *Timer) Reset(d Duration) bool */ ticker *time.Ticker runner *Runner } //新建一个进程 func NewWorker(interval time.Duration, r *Runner) *Worker { return &Worker{ //NewTicker 返回一个新的 Ticker,该 Ticker 包含一个通道字段,并会每隔时间段 d 就向该通道发送当时的时间。它会调 //整时间间隔或者丢弃 tick 信息以适应反应慢的接收者。如果d <= 0会触发panic。关闭该 Ticker 可 //以释放相关资源。 ticker: time.NewTicker(interval * time.Second), runner: r, } } func (w *Worker) startWorker() { //这里不能用range 否则会出现误差 for { select { case <-w.ticker.C: go w.runner.StartAll() } } } func Start() { //start video file cleaning r := NewRunner(3, true, VideoClearDispatcher, VideoClearExecutor) w := NewWorker(3, r) go w.startWorker() }
流程解读
从上面两个案例, 但从构造函数的设计上来看基本套路一致,同时可以显而易见的看出,构造函数的思路.
-
声明一个type(也有人习惯称其为类),假定名称为type A struct{}
-
为该type A struct{}准备几个方法func Get()和func Set()
-
声明一个独立的函数,假定为名称为NewTyepA(),
-
在NewTypeA()公共函数中返回, 实例化后的Type A struct的指针即可,
-
同时在NewTyeA()也可以为type A struct 指定各种初始化的操作
而后在其他文件中通过调用NewTypeA()即可调用TypeA中的所有方法
例如:
NewTypeA().Get()
就相当于:
// 伪代码 typeA.Get()
作者:我爱吃炒鸡,转载请注明原文链接