Shadowing a predeclared `err`?

polaris · · 1067 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi folks,</p> <p>I was looking over some code in <a href="https://golang.org/src/crypto/rsa/pkcs1v15.go?s=8750:8856#L217" rel="nofollow">crypto/rsa</a> and observed a pattern I&#39;ve avoided, assuming it to be an error:</p> <pre><code>func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { return // &lt;- Here! Implicit return of err, but err was &#34;:=&#34;&#39;d above, so which err is being returned? } </code></pre> <p>My assumption, perhaps mistaken, has been that when using <code>:=</code>, all left-hand side variables get created <em>or clobbered</em>, as if newly declared. So, I would not have written an implicit return, above, assuming that doing so would always return a zero-value for <code>err</code>, since the declared <code>err</code> for implicit return got shadowed in line 1 of the function body.</p> <p>In fact, assuming this about shadowing has discouraged me from using named return parameters in the function signature, because I assumed doing so would create additional burden on me to sanitise when I use &#34;:=&#34; on multiple return values; that is, if <code>err</code> is predeclared and a return value is not, I&#39;d feel I&#39;d need to use <code>var somevar sometype</code> prior to <code>somevar, err = somefunc()</code> rather than just using <code>somevar, err := somefunc()</code>.</p> <p>So, I&#39;m mistaken, then? Does <code>:=</code> <em>only</em> redeclare variables like <code>err</code>in <em>inner scopes where re-declaring is permitted</em>, and otherwise it just reassigns <em>values</em>? That would seem to reduce the number of gotchas, but also perhaps lead me to be more complacent; what other gotchas <em>do</em> exist besides scope-shadowing?</p> <hr/>**评论:**<br/><br/>alfredr: <pre><p>That doesn&#39;t shadow the err in the parameter list:</p> <p>As per the <a href="https://golang.org/ref/spec#Short_variable_declarations" rel="nofollow">spec</a>:</p> <blockquote> <p>Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. <strong>Redeclaration does not introduce a new variable; it just assigns a new value to the original.</strong></p> </blockquote> <p>edit: fix wording.</p></pre>cathalgarvey: <pre><p>Great, thank you! So, outside of scoping gotchas it&#39;s generally safe to use <code>:=</code> on partially pre-existing groups of variables.</p></pre>alfredr: <pre><p>Right. A typical case where you shadow is if you redeclare err in an if block e.g. </p> <pre><code>if err := something(); err != nil { // err is shadowed here } </code></pre></pre>cathalgarvey: <pre><p>Just to be clear, shadowing occurs in the <em>if clause</em> but not the <em>if body</em>, right? So, this doesn&#39;t shadow <code>err</code>, right?</p> <pre><code>if true { foo, err := something() } </code></pre></pre>velco: <pre><p>Shadowing occurs when you declare a name, which is already declated in an enclosing scope. For example, in the IfStmt </p> <blockquote> <p>IfStmt = &#34;if&#34; [ SimpleStmt &#34;;&#34; ] Expression Block [ &#34;else&#34; ( IfStmt | Block ) ] .</p> </blockquote> <p>there is an implicit block/scope, enclosing the entire if statement. Variables, declared in the SimpleStmt are declared in this block; They always shadow other variables, as no other variable are declared in this block, thus a short variable declaration can&#39;t reuse any pre-existing declaration.</p> <p>The variables, declared in the block can shadow the variables, declared in the scopes, which enclose the original if, as well as variables in the SimpleStmt, that is, declared in the implicit if block.</p> <p>So, in your example, there&#39;s no other declaration of <code>err</code> in the block, so a new variable is declared, which may shadow another <code>err</code>, declared outside the if.</p> <p><a href="http://play.golang.org/p/xKve6VvZb6" rel="nofollow">http://play.golang.org/p/xKve6VvZb6</a></p></pre>cathalgarvey: <pre><p>ugh, damn. I knew you could shadow in a <code>for</code> statement but I didn&#39;t know you could in an <code>if</code>, that&#39;s good to know.</p> <p>Is this based on the context of the block or the block itself? The if/for/switch/case or the existance of braces? eg:</p> <pre><code>foo := &#34;bar&#34; { foo := &#34;baz&#34; println(&#34;Foo is: &#34; + foo) } println(&#34;Foo is: &#34; + foo) </code></pre></pre>velco: <pre><p>It is based on what is a &#34;block&#34; and not all blocks manifest themselves via curly braces:</p> <p><a href="https://golang.org/ref/spec#Blocks" rel="nofollow">https://golang.org/ref/spec#Blocks</a></p> <p>If you are in the scope of an existing declaration <em>in the same block</em>, &#34;:=&#34; will reuse it, if there&#39;s no such declaration, &#34;:=&#34; will declare a new variable.</p> <pre><code>if x := f(); x &gt; 0 { g(x) } </code></pre> <p>is the same as</p> <pre><code>{ x := f() if x &gt; 0 { g(x) } } </code></pre></pre>TheMerovius: <pre><blockquote> <p>In fact, assuming this about shadowing has discouraged me from using named return parameters</p> </blockquote> <p>Don&#39;t avoid named return value, they are awesome (they also document when used appropriately). Avoid naked returns. They suck because they lead to such insecurities. If they&#39;d written <code>return nil, err</code> you would never have wondered. I tend to unambiguously <em>never</em> use naked returns.</p></pre>

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

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