<p>Hi, I'm looking for guidance about the "Go" way of dealing with this situation: I want to implement a callback function of type <a href="https://godoc.org/github.com/eclipse/paho.mqtt.golang#MessageHandler" rel="nofollow"><code>MessageHandler func(Client, Message)</code></a> for when a message broker receives a message. </p>
<p>Let's say I want to save the message in a database when it's received and the callback is invoked. I've only had substantial experience with duck typed languages before (and would pass the DB connection as an argument in this case), but here I can't just implement a function of my own design, because it won't be the correct type.</p>
<p>What does one typically do in Go in such situations? Pass the data into a channel declared in global scope, and have another function to handle interfacing with the DB at the other end?</p>
<hr/>**评论:**<br/><br/>nstratos: <pre><p>A good way of achieving this is to define a type that holds the DB object and has a <code>func(client MQTT.Client, msg MQTT.Message)</code> as a method. This way, the method can have access to DB or other dependencies:</p>
<pre><code>type app struct {
db DBService
}
func (app *app) messageHandler(client MQTT.Client, msg MQTT.Message) {
app.db.StoreMessage(msg)
}
</code></pre>
<p>You could also use a closure that takes <code>db</code> as a parameter and returns a <code>func(client MQTT.Client, msg MQTT.Message)</code>.</p>
<p>To learn more about the above patterns, I recommended reading <a href="http://www.alexedwards.net/blog/organising-database-access" rel="nofollow">Practical Persistence in Go: Organising Database Access</a>.</p></pre>oscooter: <pre><p>In your case what I think I'd do is create a struct that contains your sql connection and make a MessageHandler on that struct.</p>
<p>For example:</p>
<pre><code>type myDb struct {
*sql.DB
}
func (db *myDb) StoreMessage(c package.Client, m package.Message) {
// do stuff here
}
</code></pre>
<p>Then at your usage site:</p>
<pre><code>func main() {
sqlDb, err := sql.Open("driver", "conn string")
if err != nil {
log.Fatalf("Couldn't open db: %+v", err)
}
db := &myDb{ sqlDb }
package.FunctionThatNeedsHandler(db.StoreMessage)
}
</code></pre></pre>epiris: <pre><p>It sounds to me like you shouldn't use a function, but instead define an interface needed to satisfy the behavior of a MessageHandler. This way you can carry whatever state a MessageHandler may need in it's implementation- instead of binding it to a Typed function. I.E.</p>
<pre><code>type Handler interface { Handle(Client, Message) }
type dbHandler struct { db *sql.DB }
func (h *dbHandler) Handle(c Client, m Message) { h.db.Insert(...) }
</code></pre>
<p>Which you will probably notice is exactly like the http package in the std library, since it's a single method interface you can leverage the same basic Func implementation for simpler adhoc msg handlers. i.e.:</p>
<pre><code>type HandlerFunc func(Client, Message) // Same as your MessageHandler
func (fn HandlerFunc) Handle(c Client, m Message) { fn(c, m) }
</code></pre>
<p>While you're still learning what works best for you with Go it's always good to start with structs and a concrete implementation first, then when you need to accept another type find the common behavior and add an interface for it.</p></pre>
[noob question] Strict type checking is preventing me from defining the type of callback function I want. How do I write idiomatic Go to deal with this situation?
blov · · 435 次点击这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传