Ruby Nil and Zero
What's the science behind the fact that the to_i method in Ruby's NilClass instances returns zero? Returning nil or raising an exception would not be more logical开发者_如何学运维?
It fits the Ruby philosophy of permissiveness (as opposed to, for example, the strictness of Python):
nil.to_i #=> 0
"".to_i #=> 0
"123hello".to_i #=> 123
"hello".to_i #=> 0
As noted by Zabba, you can use Kernel#Integer(string) for strict conversion.
NilClass
defines #to_i
for the same reason it defines a #to_a
that returns [].
It's giving you something of the right type but an empty sort of value.
This is actually quite useful. For example:
<%= big.long.expr.nil? ? "" : big.long.expr %>
becomes:
<%= big.long.expr %>
Much nicer! (Erb is calling #to_s which, for nil, is "".) And:
if how.now.brown.cow && how.now.brown.cow[0]
how.now.brown.cow[0]
else
0
end
becomes:
how.now.brown.cow.to_a[0].to_i
The short conversions exist when only a representation is needed. The long conversions are the ones that the Ruby core methods call and they require something very close. Use them if you want a type check.
That is:
thing.to_int # only works when almost Integer already. NilClass throws NoMethodError
thing.to_i # this works for anything that cares to define a conversion
to_i
means "convert me to an integer if you can".
If you want "if you're very much integer-like, give me your integer value, else give a NoMethodError", then use .to_int
.
There's another question that asks about the difference between to_i
and to_int
, to_s
versus to_str
, etc. Let me know if you'd like me to find it for you.
The protocol of to_i
says that you must return an Integer
and you must not raise an exception. Both of your suggestions violate at least one of those rules. So, no, those would not only not be more logical, they would be simply invalid.
Note, however, that nil
does not respond to to_int
. If it did respond to to_int
, that would, indeed, be "illogical".
If you happen to be in Rails then you can use try
:
nil.to_i # => 0
nil.try :to_i # => nil
A concise Ruby 2.3+ method for returning nil
for nil.to_i
instead of 0, is to use the safe navigation operator:
irb(main):001:0> nil.to_i
=> 0
irb(main):002:0> nil&.to_i
=> nil
精彩评论