问题
Why aren't these two statements equivalent?
defined? foo ? foo << "bar" : foo = ["bar"]
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:
- defined? foo ? foo << "bar" : foo = ["bar"]
- 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