Should Go have a Ternary Operator? Or was it left out intentionally?

xuanbao · · 541 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I&#39;m a newbie to Go (coming from Java). I was surprised to see that Go doesn&#39;t have a <a href="https://en.wikipedia.org/wiki/%3F:" rel="nofollow">ternary operator</a>. The <a href="https://golang.org/doc/faq#Does_Go_have_a_ternary_form" rel="nofollow">FAQ</a> just says that Go doesn&#39;t have :?, then says that you can use the standard if-else chain to achieve it.</p> <p>I understand that not using :? might improve readability, but it&#39;s still really neat! So why was it left out? And should Go have it? What do you guys think?</p> <hr/>**评论:**<br/><br/>dgryski: <pre><p>My favourite arguments against the ternary operator is:</p> <p><code>int median(int[5] a){ return a[a[0]&lt;a[1]?a[2]&lt;a[3]?a[0]&lt;a[2]?a[1]&lt;a[4]?a[1]&lt;a[2]?a[2]&lt;a[4]?2:4:a[1]&lt;a[3]?1:3:a[2]&lt;a[4]?a[3]&lt;a[4]?3:4:a[1]&lt;a[2]?1:2:a[3]&lt;a[4]?a[0]&lt;a[3]?a[1]&lt;a[3]?1:3:a[0]&lt;a[4]?0:4:a[0]&lt;a[4]?a[1]&lt;a[4]?1:4:a[0]&lt;a[3]?0:3:a[0]&lt;a[3]?a[1]&lt;a[4]?a[1]&lt;a[3]?a[3]&lt;a[4]?3:4:a[1]&lt;a[2]?1:2:a[3]&lt;a[4]?a[2]&lt;a[4]?2:4:a[1]&lt;a[3]?1:3:a[2]&lt;a[4]?a[0]&lt;a[2]?a[1]&lt;a[2]?1:2:a[0]&lt;a[4]?0:4:a[0]&lt;a[4]?a[1]&lt;a[4]?1:4:a[0]&lt;a[2]?0:2:a[2]&lt;a[3]?a[0]&lt;a[3]?a[2]&lt;a[4]?a[0]&lt;a[4]?a[0]&lt;a[2]?2:0:a[1]&lt;a[4]?4:1:a[0]&lt;a[2]?a[0]&lt;a[4]?4:0:a[1]&lt;a[2]?2:1:a[1]&lt;a[4]?a[3]&lt;a[4]?a[1]&lt;a[3]?3:1:a[2]&lt;a[4]?4:2:a[1]&lt;a[3]?a[1]&lt;a[2]?2:1:a[3]&lt;a[4]?4:3:a[0]&lt;a[2]?a[3]&lt;a[4]?a[0]&lt;a[4]?a[0]&lt;a[3]?3:0:a[1]&lt;a[4]?4:1:a[0]&lt;a[3]?a[0]&lt;a[4]?4:0:a[1]&lt;a[3]?3:1:a[1]&lt;a[4]?a[2]&lt;a[4]?a[1]&lt;a[2]?2:1:a[3]&lt;a[4]?4:3:a[1]&lt;a[2]?a[1]&lt;a[3]?3:1:a[2]&lt;a[4]?4:2]; } </code></p> <p>I saw this code proposed in total seriousness in a programming language discussion thread.</p></pre>RalphCorderoy: <pre><p>Other arguments aside, the grammar <em>could</em> stop that happening by allowing only one use.</p></pre>drvd: <pre><p>A simple ?: is neat and useful.</p> <p>But there is no (sensible) way to prevent ugly nesting:</p> <pre><code>(foo() ? a() : b()) ? (bar() ? 7 : -1) : wuz() ? g() : 8 </code></pre> <p>Which doesn&#39;t simply hurts readability, it kills it. </p></pre>1-21Gigawatts: <pre><p>I&#39;ve only ever used it in moderation, so I didn&#39;t consider that people would nest ?: inside of ?: inside of...</p> <p>Yeah, that makes sense.</p></pre>CaffeineComa: <pre><p>Wow, good point. I used to wonder the same thing as OP, since the judicious use of ternary is a good way to cut down on LoC and (IMHO) actually make code short and readable. But it never really occurred to me that someone would abuse it in the way you outlined. I wonder if it&#39;s possible for some future version of the Go compiler to only allow a &#34;single level&#34; of ternary.</p></pre>natefinch: <pre><p>We had a critical security bug in production for years at my last job because of a misused ternary that never would have happened if someone had just used an if statement. I&#39;m happy it doesn&#39;t exist in go, even if it makes some things a little bit more verbose.</p></pre>tmornini: <pre><p>If the tests were complete...</p> <p>I&#39;m confident the ternary operator was cut in favor of minimalism, not due to a belief or actual evidence that it increases bug rates...</p></pre>NichtMitCommander: <pre><p>Not having a ternary operator is a feature of Go that I am happy about, especially if I have to read other peoples code.</p></pre>Ainar-G: <pre><p>Here is an example (from Toonz source code) that shows why ternary operator may be a bad idea:</p> <pre><code>void rgb_to_lightness_( const double re, const double gr, const double bl, double &amp;li) { li=((re &lt; gr) ? ((gr &lt; bl) ? bl : gr) : ((re &lt; bl) ? bl : re) + (gr &lt; re) ? ((bl &lt; gr) ? bl : gr) : ((bl &lt; re) ? bl : re)) / 2.0; } </code></pre></pre>weberc2: <pre><p>I think the philosophy regarding readability in Go is that &#39;explicit&#39; is more readable than &#39;terse&#39;. Especially when supporting &#39;terse&#39; adds complexity to the parser.</p></pre>MrSaints: <pre><p>&#34;The&#34; C-like ternary operator was not included because of readability issues, and it&#39;s pretty easy to abuse. I&#39;m personally apathetic about it. I don&#39;t think it&#39;ll add a lot of value.</p> <p>BTW, Go does have ternary operators (not &#34;the&#34; conditional expression though). e.g. <code>s, ok := v.(string)</code></p></pre>velco: <pre><p>The only expression in this snippet is the type assertion, which has one operand.</p> <p>&#34;n-ary operator&#34; means &#34;with n operands&#34;</p></pre>MrSaints: <pre><p>By your last statement, that snippet is indeed an example of a ternary operator in Go (albeit, not the one that most languages, and people have been accustomed to, &#34;the&#34; ?: one). It is an assignment operator (in the context of a type assertion) which has 3 operands. Go is filled with left-associative ternary operators.</p></pre>velco: <pre><p>No. The only operand is <code>v</code>. The operation is &#34;type assertion to <code>string</code>&#34;; The type <code>string</code> is (arguably) not an operand, as you can&#39;t place a variable there. The variables <code>s</code> and <code>ok</code> are not <em>operands</em>, they are the <em>results</em> of the operation. And assignment is not an operator in Go, as the assignment in Go is not an expression.</p></pre>MrSaints: <pre><p>I can see where you&#39;re coming from, but you seem really misinformed.</p> <blockquote> <p>s and ok are not operands, they are the results of the operation</p> </blockquote> <p>Based on the <a href="https://golang.org/ref/spec#identifier" rel="nofollow">specs</a>, they are indeed operands. And it makes explicit <a href="https://golang.org/ref/spec#Assignments" rel="nofollow">references</a> to them, e.g.</p> <ul> <li>&#34;The blank identifier may appear as an operand only on the left-hand side of an assignment.&#34;</li> <li>&#34;The right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on the left hand side must match the number of values.&#34;</li> <li>&#34;When evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.&#34;</li> </ul> <blockquote> <p>And assignment is not an operator in Go, as the assignment in Go is not an expression.</p> </blockquote> <p>I&#39;d like to know where you learnt that. Unless I&#39;ve misunderstood what you&#39;re saying, you&#39;re suggesting that an <a href="https://en.wikipedia.org/wiki/Operator_(computer_programming" rel="nofollow">operator</a>) (&#34;More involved examples include assignment (usually = or :=)&#34;) is not an operator unless it&#39;s an expression.</p> <p>The two are not equivalent as indeed, &#34;an expression specifies the computation of a value by applying operators and functions to operands.&#34;</p> <p>Anyway, I think this is starting to become a fruitless contention over semantics, and you don&#39;t have to take <a href="https://groups.google.com/d/msg/golang-nuts/w1dPeHFSp9g/wxhKsQheQ7UJ" rel="nofollow">my word</a> for it.</p></pre>velco: <pre><p>This <a href="https://golang.org/ref/spec#Operators" rel="nofollow">https://golang.org/ref/spec#Operators</a> is the complete list of operators in Go. Neither of them has three or more operands.</p> <p>I will agree that not only expressions can have operands.</p> <p>And something that Mr.Pike says is true, is not true just because Mr.Pike says it. Of course, you&#39;re completely free to rely on authority, rather than logic.</p></pre>MrSaints: <pre><p>I&#39;m relying on your original statement that <code>&#34;n-ary operator&#34; means &#34;with n operands&#34;</code>, and from my understanding, it fits the logic (FYI, the <a href="https://github.com/golang/go/blob/master/src/go/token/token.go#L70" rel="nofollow">tokenizer</a> considers it an operator).. But yea, agree to disagree.</p></pre>Tasssadar: <pre><p>I really don&#39;t know about readability. For me, this...</p> <pre><code>func (d *decoder) decodeHttps(s *tcpStream, t time.Time) { prefix := s.dstPort == 443 ? HttpsRequest : HttpsResponse if s.reported || !d.dumpTcpBlockStart(s, t, prefix) { return } s.reported = true fmt.Fprintf(d.out, &#34;\n&#34;) } </code></pre> <p>..is much more readable than this: </p> <pre><code>func (d *decoder) decodeHttps(s *tcpStream, t time.Time) { var prefix = HttpsRequest if s.dstPort == 443 { prefix = HttpsResponse } if s.reported || !d.dumpTcpBlockStart(s, t, prefix) { return } s.reported = true fmt.Fprintf(d.out, &#34;\n&#34;) } </code></pre> <p>or even this:</p> <pre><code>func (d *decoder) decodeHttps(s *tcpStream, t time.Time) { var prefix string if s.dstPort == 443 { prefix = HttpsResponse } else { prefix = HttpRequest } if s.reported || !d.dumpTcpBlockStart(s, t, prefix) { return } s.reported = true fmt.Fprintf(d.out, &#34;\n&#34;) } </code></pre> <p>...like, you just made me read 3-4 more lines and extra indentation level for something so simple. Why.</p> <p>Yes, it is extremely easy to abuse<sup><sup>don&#39;t,</sup></sup> <sup><sup>then?</sup></sup> . So is goto, and it is present in golang in properly limited form.</p> <p>With that said, I have no idea how difficult is it to add to golang compiler - if it would add a lot of unnecessary clutter, then I&#39;m all for omitting it.</p></pre>

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

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