Go语言中type func()的的使用分析

在Go语言中可以通过type来定义变量类型,在学习源码的过程中经常会看到一种type func()的定义方式,刚开始的时候有点难以理解,现在对这种方法做一下分析。

1.案例分析

在使用**“github.com/robfig/cron”**库创建定时任务时就会用到type func()这种定义类型的方式:

func CreateCron() {
	//创建定时任务
	i := 0
	c := cron.New()
	spec := "*/5 * * * * ?"
	// AddFunc的第二个参数就是函数类型
	if err := c.AddFunc(spec, func() {
		i++
		log.Println("cron running:", i)
	}); err != nil {
		log.Println(err)
	}
	c.Start()
}

查看AddFunc()源码,可以发现,AddFunc方法的第二个参数时func()类型:

// AddFunc adds a func to the Cron to be run on the given schedule.
func (c *Cron) AddFunc(spec string, cmd func()) error {
	return c.AddJob(spec, FuncJob(cmd))
}

这个方法调用了AddJob(spec, FuncJob(cmd)),AddJob方法的第二个参数是Job类型,因此在调用AddJob方法时通过 FuncJob(cmd)将cmd转换为FuncJob类型,而Job是一个接口,FuncJob实现了Job接口的Run方法,而Run方法就做了一件事就是执行FunJob这个函数。

// A wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// Job is an interface for submitted cron jobs.
type Job interface {
	Run()
}

分析到这里,大家应该明白了type func()类型的使用方法,但是这里的func()类型是没有参数的,如果函数类型中有参数,那这个参数是如何传递的?下面再说一个案例:

func Http() {
	http.HandleFunc("/", h)
}
func h(w http.ResponseWriter, r *http.Request) {
	return
}

上面的HandleFunc方法的第二个参数是一个带参数的函数类型

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

在HandleFunc方法中使用HandlerFunc将传进来的函数强制转换为HandlerFunc类型,HandlerFunc类型实现了Handler接口的ServerHTTP方法,这样就可以调用Handle方法了。

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

注意:这个案例中传入的函数是有参数的,在这里参数的作用相当于声明参数,在使用函数类型的变量时,并不能传入参数。

2. 应用

说了这么多,我们来应用一下type func()的使用方法。

// 定义ISay接口,这个接口实现了Say方法
type ISay interface {
	Say()
}

// 定义函数类型的SayFunc
type SayFunc func()

// 实现ISay接口的Say方法,注意这里不能使用*SayFunc,否则会报错
func (s SayFunc) Say() {
	s()
}

// 入口函数具体执行的函数
func say(iSay ISay) {
	iSay.Say()
}

// 入口函数
func Say(handler func()){
	say(SayFunc(handler))
}

// 定义一个函数
func SayHello() {
	fmt.Println("Hello World")
}
func main() {
	Say(SayHello)
}

这个例子使用函数类型的变量,最终输出了一个Hello World,看起来好像没有必要,直接调用SayHello函数不是更简单吗,是的,这样更简单,但是如果你要写一个库,他必须要让使用者可以自定义方法执行的步骤,比如案例一中,定时任务具体执行的操作要由使用者定义,那么就必须要用到函数类型的参数,这样用户就可以很方便的自定义定时任务的具体操作,案例二也是同样的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Go 语言,通常使用 DAO(Data Access Object)模式来访问数据库。DAO 层是一个独立的模块,负责与数据库交互,提供对外的 API,供上层的 Service 层调用。 下面是一个简单的示例,演示如何在 Service 使用 DAO 层的数据: 首先,定义一个 DAO 接口,包含对数据库进行增删改查的方法: ```go type UserDao interface { Get(id int) (*User, error) Create(user *User) error Update(id int, user *User) error Delete(id int) error } ``` 然后,实现这个接口的具体逻辑,比如使用 GORM 操作 MySQL 数据库: ```go type UserDaoImpl struct { db *gorm.DB } func (dao *UserDaoImpl) Get(id int) (*User, error) { var user User if err := dao.db.Where("id = ?", id).Find(&user).Error; err != nil { return nil, err } return &user, nil } func (dao *UserDaoImpl) Create(user *User) error { if err := dao.db.Create(user).Error; err != nil { return err } return nil } func (dao *UserDaoImpl) Update(id int, user *User) error { if err := dao.db.Model(&User{}).Where("id = ?", id).Updates(user).Error; err != nil { return err } return nil } func (dao *UserDaoImpl) Delete(id int) error { if err := dao.db.Where("id = ?", id).Delete(&User{}).Error; err != nil { return err } return nil } ``` 最后,在 Service 使用这个 DAO 接口: ```go type UserService struct { userDao UserDao } func (s *UserService) GetUser(id int) (*User, error) { return s.userDao.Get(id) } func (s *UserService) CreateUser(user *User) error { return s.userDao.Create(user) } func (s *UserService) UpdateUser(id int, user *User) error { return s.userDao.Update(id, user) } func (s *UserService) DeleteUser(id int) error { return s.userDao.Delete(id) } ``` 这样,Service 层就可以通过 DAO 层来访问数据库了。在实际开发,我们通常会使用依赖注入的方式,将 DAO 对象注入到 Service ,以便更好地管理和测试代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值