[Help] Defining a type as a function, and then adding a function

polaris · · 471 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hey!</p> <p>I read a tutorial about HTTP handler wrappers and I came across an example that looked like this</p> <pre><code>type appHandler func(http.ResponseWriter, *http.Request) (int, error) // Our appHandler type will now satisify http.Handler func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { status, err := fn(w, r) ... ... } </code></pre> <p> </p> <ol> <li>After the first line, what is <code>appHandler</code> and how is it useful at that point?</li> <li>After the function declaration, what is <code>appHandler</code> and how do I use it? </li> </ol> <p>It seems you define a function with a function as it&#39;s context argument. It seems really weird to me, so I guess theres a meaning that I don&#39;t get. </p> <p>Thanks for the help!</p> <hr/>**评论:**<br/><br/>alaskacodes: <pre><p>It&#39;s a function type. Think of &#34;appHandler&#34; as a named function signature. You&#39;re saying &#34;a function can be an apphandler if it satisfies this signature&#34;. You can think of it as a bit like an interface in that anonymous functions can implicitly satisfy it, so long as they fit the signature exactly. In other words, if you define a function that takes the same types in the same order and returns the same types in the same order, then it can be implicitly or explicitly converted into a value of that type:</p> <p><a href="https://play.golang.org/p/Dmw7YugD74">https://play.golang.org/p/Dmw7YugD74</a></p> <pre><code>package main import &#34;fmt&#34; type changer func(int) int func runChanger(c changer, val int) int { return c(val) } func main() { //Implicit conversion timesTwo := func(v int) int { return v * 2 } fmt.Println(runChanger(timesTwo, 5)) //Explicit conversion subThree := changer(func(v int) int { return v - 3 }) fmt.Println(runChanger(subThree, 5)) } </code></pre> <p>Since <code>runChanger</code> takes a value of type <code>changer</code>, both <code>timesTwo</code> and <code>subThree</code> can be passed to it because they satisfy the function signature exactly.</p> <p>As with any type conversion, if the target type has methods, those will be accessible as well, but only after the conversion has been performed: </p> <p><a href="https://play.golang.org/p/7qY05zE6XC">https://play.golang.org/p/7qY05zE6XC</a></p> <p>This is important to note if you&#39;re attempting to satisfy an interface.</p> <p>For more on this (and why you&#39;d want to do it), check out the following: <a href="http://jordanorelli.com/post/42369331748/function-types-in-go-golang">http://jordanorelli.com/post/42369331748/function-types-in-go-golang</a></p></pre>lannor: <pre><p>Thanks, I get that now. Good explanation.</p> <p>But I don&#39;t really feel that I get my second question answered. Maybe I missed something in your description or you maybe didn&#39;t answer that fully. Would you mind elaborating on the second question as well? </p> <p>To clarify, what happens with the types and possibilities after the declaration of <code>ServeHTTP</code> with a <code>appHandler</code> as context?</p> <p>Thanks!</p></pre>alaskacodes: <pre><p>Well, now your type has a method, like any other type. Only, in this case, your receiver <code>fn</code> is itself a function that can be called. By declaring a method called <code>ServeHTTP</code> on your function, you satisfy the <a href="https://golang.org/pkg/net/http/#Handler" rel="nofollow">http.Handler</a> interface, which means you can use it anywhere a <code>http.Handler</code> is required. Like, for instance, as the <code>Handler</code> member of an <a href="https://golang.org/pkg/net/http/#Server" rel="nofollow">http.Server</a></p></pre>FEiN: <pre><p>It allows you to convert a function to the type you defined, which has methods on it like other types can. So that way your new type implements an interface, in this case http.Handler. Its a really neat thing to use for single method interfaces.</p> <p>So now instead of defining another handler type you can use your existing type, like this</p> <pre><code>func main() { http.ListenAndServe(&#34;:6060&#34;, appHandler(func(rw http.ResponseWriter, r *http.Request) (int, error) { // do something return 200, nil })) } </code></pre></pre>arschles: <pre><p>just out of curiosity, in which tutorial did you find that code?</p></pre>tdewolff: <pre><p>It is used in the standard library! <a href="https://golang.org/src/net/http/server.go?s=41267:41314#L1408" rel="nofollow">https://golang.org/src/net/http/server.go?s=41267:41314#L1408</a></p></pre>arschles: <pre><p>Haha! Yes it is. I was assuming that the OP wasn&#39;t referring to HandlerFunc</p></pre>lannor: <pre><p>I found it here: <a href="https://elithrar.github.io/article/custom-handlers-avoiding-globals/" rel="nofollow">https://elithrar.github.io/article/custom-handlers-avoiding-globals/</a></p></pre>mc_hammerd: <pre><p>1) its a custom type.</p> <p>like <code>int</code> and <code>string</code> are built-in types or <code>type IntArray []int</code> is a custom type</p> <p>2) it saves you keystrokes</p> <p>now you can write</p> <pre><code>func mynewfunc(fn apphandler) { fn() } </code></pre> <p>or</p> <pre><code>fn := apphandler { // dostuff } </code></pre></pre>alaskacodes: <pre><blockquote> <p>now you can write</p> </blockquote> <pre><code>fn := apphandler { // dostuff } </code></pre> <p>You can&#39;t do that. You&#39;ll get a syntax error. Did you mean:</p> <pre><code>fn := apphandler( func(w http.ResponseWriter, r *http.Request) (int, error) { // dostuff }) </code></pre> <p>Because that&#39;s the only way that will work as a type conversion. See here: <a href="https://groups.google.com/forum/#!topic/golang-nuts/deG9_iVwC3Y">https://groups.google.com/forum/#!topic/golang-nuts/deG9_iVwC3Y</a> Anonymous functions need a <code>func</code> keyword and parameter declarations.</p> <p>Using this syntax would introduce ambiguity between map/slice literals and anonymous functions, which would require a special case in the parser and make tooling much more difficult.</p></pre>mc_hammerd: <pre><p>thx i had never tried it. that is the correct syntax :). cheers.</p></pre>

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

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