<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's context argument. It seems really weird to me, so I guess theres a meaning that I don't get. </p>
<p>Thanks for the help!</p>
<hr/>**评论:**<br/><br/>alaskacodes: <pre><p>It's a function type. Think of "appHandler" as a named function signature. You're saying "a function can be an apphandler if it satisfies this signature". 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 "fmt"
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're attempting to satisfy an interface.</p>
<p>For more on this (and why you'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't really feel that I get my second question answered. Maybe I missed something in your description or you maybe didn'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(":6060", 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'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't do that. You'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'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
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传