GoLang构造函数

Stella981
• 阅读 697

[TOC]

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()
}

流程解读

从上面两个案例, 但从构造函数的设计上来看基本套路一致,同时可以显而易见的看出,构造函数的思路.

  1. 声明一个type(也有人习惯称其为类),假定名称为type A struct{}

  2. 为该type A struct{}准备几个方法func Get()和func Set()

  3. 声明一个独立的函数,假定为名称为NewTyepA(),

  4. 在NewTypeA()公共函数中返回, 实例化后的Type A struct的指针即可,

  5. 同时在NewTyeA()也可以为type A struct 指定各种初始化的操作

而后在其他文件中通过调用NewTypeA()即可调用TypeA中的所有方法

例如:

NewTypeA().Get()

就相当于:

// 伪代码
typeA.Get()
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
JS基础——原型和原型链
1、相关知识点(1)构造函数 (函数名首字母大写表示构造函数)functionFoo(name,age){this.namename;this.ageage;this.class'class';//returnthis;默认有这一行,浏览器帮忙做
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这