Go 感受回调函数的魅力

时间:2021-04-09 12:53:58   收藏:0   阅读:0

Go 感受回调函数的魅力

在用mqtt的SDK时候,感觉回调一脸蒙蔽,在自己实现之后,还是有点意思的

官方sdk原始代码

/*
 * Copyright (c) 2013 IBM Corp.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Seth Hoenig
 *    Allan Stockdill-Mander
 *    Mike Robertson
 */

package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/eclipse/paho.mqtt.golang"
)

var f mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	fmt.Printf("TOPIC: %s\n", msg.Topic())
	fmt.Printf("MSG: %s\n", msg.Payload())
}

func main() {
	mqtt.DEBUG = log.New(os.Stdout, "", 0)
	mqtt.ERROR = log.New(os.Stdout, "", 0)
	opts := mqtt.NewClientOptions().AddBroker("tcp://iot.eclipse.org:1883").SetClientID("gotrivial")
	opts.SetKeepAlive(2 * time.Second)
	opts.SetDefaultPublishHandler(f)
	opts.SetPingTimeout(1 * time.Second)

	c := mqtt.NewClient(opts)
	if token := c.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}

	// 注意下面的f
	if token := c.Subscribe("go-mqtt/sample", 0, f); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}

	for i := 0; i < 5; i++ {
		text := fmt.Sprintf("this is msg #%d!", i)
		token := c.Publish("go-mqtt/sample", 0, false, text)
		token.Wait()
	}

	time.Sleep(6 * time.Second)

	if token := c.Unsubscribe("go-mqtt/sample"); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}

	c.Disconnect(250)

	time.Sleep(1 * time.Second)
}

我自己还原的

mq.go

package mq

type Sub func(c *Client, mgs []byte)

type Client struct {
	SubData chan []byte
}

func NewClient() *Client {
	return &Client{SubData:make(chan []byte, 1)}
}

func (c *Client)Subscribe(topic string, qos int, fn Sub)  {
	go func() {
		for {
			select {
			case data := <- c.SubData:
				// 可以在这里面进行进一步处理
				fn(c, data)
			}
		}
	}()
}

main.go

package main

import (
	"aaa/mq"
	"encoding/json"
	"fmt"
	"log"
	"time"
)

const _defaultTopic  = "+/a"

type Data struct {
	Topic string
	PayLoad []byte
}

var callback mq.Sub = func(client *mq.Client, msg []byte) {
	var d Data
	err := json.Unmarshal(msg,&d)
	if err != nil {
		log.Println(err)
	}

	fmt.Println("获取的topic", d.Topic)
	fmt.Println("获取的数据", string(d.PayLoad))
}

func main()  {
	client := mq.NewClient()
	client.Subscribe(_defaultTopic, 1, callback)

	// 模拟pub数据
	for {
		d := Data{
			Topic:   _defaultTopic,
			PayLoad: []byte(time.Now().String()),
		}

		marshal, err := json.Marshal(d)
		if err != nil {
			log.Println(err)
		}

		client.SubData<- marshal
		time.Sleep(time.Millisecond * 500)
	}
}

理解

回调函数在结构上出来,传进去的参数让用户自己处理

有意思的回调理解

打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!