[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 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi, I&#39;m looking for guidance about the &#34;Go&#34; 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&#39;s say I want to save the message in a database when it&#39;s received and the callback is invoked. I&#39;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&#39;t just implement a function of my own design, because it won&#39;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&#39;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(&#34;driver&#34;, &#34;conn string&#34;) if err != nil { log.Fatalf(&#34;Couldn&#39;t open db: %+v&#34;, err) } db := &amp;myDb{ sqlDb } package.FunctionThatNeedsHandler(db.StoreMessage) } </code></pre></pre>epiris: <pre><p>It sounds to me like you shouldn&#39;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&#39;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&#39;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&#39;re still learning what works best for you with Go it&#39;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>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

435 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传