开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜