Ruby ternary operator

耗尽温柔 提交于 2019-12-25 11:24:30

问题


Why aren't these two statements equivalent?

  1. defined? foo ? foo << "bar" : foo = ["bar"]
  2. if (defined? foo) then foo << "bar" else foo = ["bar"] end

First statement:

irb(main):001:0> defined? foo ? foo << "bar" : foo = ["bar"]
=> nil
irb(main):002:0> foo
=> nil
irb(main):003:0> defined? foo ? foo << "bar" : foo = ["bar"]
=> "expression"
irb(main):004:0> foo
=> ["bar"]

Second statement:

irb(main):001:0> if (defined? foo) then foo << "bar" else foo = ["bar"] end
=> ["bar"]
irb(main):002:0> foo
=> ["bar"]
irb(main):003:0> if (defined? foo) then foo << "bar" else foo = ["bar"] end
=> ["bar", "bar"]
irb(main):004:0> foo
=> ["bar", "bar"]

These sessions are with JRuby 1.5.0 (should be equivalent to native Ruby 1.8.7). I see slightly different behavior with native ruby 1.9.1: statement #1 never defines foo even when running it twice.


回答1:


Because the first evaluates to:

defined?(foo ? foo << "bar" : foo = ["bar"])

Why that returns nil, I have no clue...

The fix is simply to do:

(defined? foo) ? foo << "bar" : foo = ["bar"]



回答2:


  1. defined? foo ? foo << "bar" : foo = ["bar"]
  2. if (defined? foo) then foo << "bar" else foo = ["bar"] end

In either case, your code could probably be simplified. Based on the two samples above it looks like there'd be an enclosing loop of some sort. Rather than try to create foo inside it and initialize to the first ['bar'], I'd do something like:

foo = []
... start some loop ...
  foo << bar
... end some loop ...

Or, if you don't like breaking up the initializer from where you append to the array:

(foo ||= []) << "bar"

This second way is a bit "Perlish", but it's not so far gone from the Ruby-way to be undecipherable.



来源:https://stackoverflow.com/questions/5248228/ruby-ternary-operator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!