I am learning Go and decided to rewrite a MQTT orchestrator which I originally wrote in Python. The very basic part works fine:
package main
import (
"fmt"
"time"
"os"
MQTT "github.com/eclipse/paho.mqtt.golang"
log "github.com/sirupsen/logrus"
)
// definitions for a switch
type Switch struct {
topic string
state int
}
func allEvents(client MQTT.Client, msg MQTT.Message) {
log.WithFields(log.Fields{"topic": msg.Topic(), "payload": fmt.Sprintf("%s", msg.Payload())}).Info()
}
func initMQTT() MQTT.Client {
opts := MQTT.NewClientOptions()
opts.AddBroker("tcp://mqtt.example.com:1883")
opts.SetClientID("go-dispatcher")
opts.SetCleanSession(true)
client := MQTT.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
log.Info("connected to MQTT broker")
return client
}
func main() {
// this is that part I want to modify later in the question
c := initMQTT()
if token := c.Subscribe("#", 0, allEvents); token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
os.Exit(1)
}
time.Sleep(100000 * time.Hour)
}
Having used pointers in a distant past with C, I wanted to modify the program to pass, in the initialization part, the client by reference (more as a learning experience, the first code looks better to me)
package main
import (
"fmt"
"time"
"os"
MQTT "github.com/eclipse/paho.mqtt.golang"
log "github.com/sirupsen/logrus"
)
// definitions for a switch
type Switch struct {
topic string
state int
}
func allEvents(client MQTT.Client, msg MQTT.Message) {
log.WithFields(log.Fields{"topic": msg.Topic(), "payload": fmt.Sprintf("%s", msg.Payload())}).Info()
}
// this time we get a pointer and do not return anything
func initMQTT(client *MQTT.Client) {
opts := MQTT.NewClientOptions()
opts.AddBroker("tcp://mqtt.example.com:1883")
opts.SetClientID("go-dispatcher")
opts.SetCleanSession(true)
client = MQTT.NewClient(opts)
if token := *client.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
log.Info("connected to MQTT broker")
}
func main() {
// the client is defined in main()
var c MQTT.Client
// and passed by reference so that the function modifies it
initMQTT(&c)
if token := c.Subscribe("#", 0, allEvents); token.Wait() && token.Error() != nil {
fmt.Println(token.Error())
os.Exit(1)
}
time.Sleep(100000 * time.Hour)
}
It fails to compile with
# command-line-arguments
.\main.go:29:9: cannot use mqtt.NewClient(opts) (type mqtt.Client) as type *mqtt.Client in assignment:
*mqtt.Client is pointer to interface, not interface
.\main.go:30:21: client.Connect undefined (type *mqtt.Client is pointer to interface, not interface)
Following advice form another question, I tried to remove &
and *
(blindly to start with, to tell the truth), and get a runtime error
time="2018-05-26T21:02:20+02:00" level=info msg="connected to MQTT broker"
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x604486]
goroutine 1 [running]:
main.main()
D:/Seafile/dev/Go/src/perso/domotique.dispatcher/main.go:39 +0x36
I though that since I defined c
, I could just pass it as a reference but apparently the C-way is not the right one here? (it is usually in the examples I read)