<p>Any ideas on what I'm doing wrong here?</p>
<p><a href="https://play.golang.org/p/8_bLwky0Rs">Playground Example</a></p>
<p>I was attempting to consolidate some testing code into a single method which would trigger a GET or POST based on whether a map of parameters was passed in. The problem is that it appears that the "zero" value for the pointer to a strings.Reader object (the request body) is not actually being interpreted as a nil value when it is passed as a method parameter to the http.NewRequest function (even though it tests as being nil in the current function). Explicitly setting the variable to nil also results in a panic.</p>
<p>On the other hand, if I call <code>http.NewRequest(method, route, nil)</code>, there is no panic.</p>
<p>There is, of course, the workaround of branching on the passed map and having two calls to <code>http.NewRequest</code>, but that seems a bit redundant.</p>
<hr/>**评论:**<br/><br/>pappogeomys: <pre><p>This is in the FAQ, but usually arrises from error values: <a href="http://golang.org/doc/faq#nil_error">http://golang.org/doc/faq#nil_error</a></p>
<p>The zero value for <code>*strings.Reader</code> is being wrapped in an <code>io.Reader</code> when you pass it into the NewRequest function. This means although the <code>io.Reader</code> internal "value" is <code>nil</code>, the "type" is set to <code>*strings.Reader</code>, making the interface as a whole not equal to <code>nil</code>. </p>
<p>You need to explicitly pass in <code>nil</code> to be safe.
<a href="https://play.golang.org/p/u5b58KZsOE">https://play.golang.org/p/u5b58KZsOE</a></p></pre>dominic_failure: <pre><p>Wow. Talk about an unforeseeable side effect of reflection. One would expect that a nil value, when <a href="https://golang.org/ref/spec#Calls" rel="nofollow">passed by value</a> into a function would be equivalent to passing the nil literal.</p>
<p>I've been operating under the assumption that interfaces were there purely for the compiler and type system, guess this is a wakeup call to dig even deeper into reflection, even if I rarely use it.</p>
<p>In any case, thanks for pointing me in the right direction!</p></pre>pappogeomys: <pre><p>You don't need to go into reflection to understand this (though the same principals apply, you need to understand Go interfaces.). Read that faq entry carefully, as it's explained in full.</p>
<p>And of course I forgot another option which <a href="/u/anossov" rel="nofollow">/u/anossov</a> mentions, declare your <code>requestReader</code> as the interface type itself -- <code>io.Reader</code>.</p></pre>dominic_failure: <pre><p>Sure, but the underlying issue is caused by a decision about how to make interfaces support reflection by implementing them as a box for the underlying value, not the interface specification itself (which is remarkably <a href="https://golang.org/ref/spec#Interface_types" rel="nofollow">simple</a>, in spite of the examples).</p>
<p>This indicates that there may be other implementation niggles caused by supporting reflection; being cognizant of all the possible actions through reflection will let me infer more about the underlying implementation.</p></pre>pappogeomys: <pre><p>Well, a language with reflection needs to support reflection, so that's always a given.</p>
<p>But here, interfaces themselves don't contain anything extra just for reflection. You may be thinking of <a href="http://golang.org/ref/spec#Type_assertions" rel="nofollow">Type Assertions</a>, which are a core part of the language, and don't rely on reflection. Without the original type (and <a href="http://golang.org/ref/spec#Method_sets" rel="nofollow">method set</a>) from the interface, you couldn't statically assert an interface to a type or another interface, hence removing a lot of their constructive value (the standard library alone probably contains thousands of type assertions).</p></pre>rebel581: <pre><p>Interesting to know, but is there a reason why Go was designed this way? It seems like a huge gotcha and I don't understand why all nil comparisons aren't considered the same. I can't think of a reason where having an interface with a type but a nil value is helpful other than creating potential places to panic. In this case, the calling function performs a check for nil and then panics because a nil value was passed in.</p></pre>pappogeomys: <pre><p>First, a typed nil is still a valid value, and you can call methods on a nil value that don't dereference a pointer receiver. If a nil value was wrapped in an interface, it can be still useful to determine what that value was.</p>
<p>An interface is also a value, and an interface value that contains <code>{nil, Type}</code> is not the same as an interface that contains <code>{nil, nil}</code>. Having them both evaluate equal to <code>nil</code> would be more confusing. Even more confusing would be if <code>{nil, TypeA} == nil</code> and <code>{nil, TypeB} == nil</code>, but <code>{nil, TypeA} != {nil, TypeB}</code>, breaking transitive equality. </p>
<p>It's a gotcha that Go programmers all see at some point, but it's in the FAQ, and once you understand interfaces it becomes very clear as to why it behaves the way it does.</p></pre>anossov: <pre><p>Instead of passing an expicit <code>nil</code> you can also declare <code>var requestReader *strings.Reader</code> as <code>var requestReader io.Reader</code>.</p></pre>dominic_failure: <pre><p>Elegant. Thank you!</p></pre>klauspost: <pre><p>Have a look at <a href="https://golang.org/doc/faq#nil_error" rel="nofollow">Why is my nil error value not equal to nil?</a>. </p>
<p>Once you send a nil "<em>strings.Reader" it is transformed to an interface with type "</em>strings.Reader" and value "nil", and as the FAQ states: "Such an interface value will therefore be non-nil even when the pointer inside is nil."</p>
<p>I fixed it up. Also, no need to send pointers to maps: <a href="https://play.golang.org/p/4ZaPD4leNr" rel="nofollow">https://play.golang.org/p/4ZaPD4leNr</a></p></pre>dominic_failure: <pre><p>Thanks for the reminder on the map pointer!</p></pre>
Refactoring help requested - unset pointer registers as nil in current function, but not in called functions
agolangf · · 651 次点击这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传