当你重新定义一个方法时它什么时候应该工作?

mcw*_*bly 2 ruby

Ruby Koans中,about_open_classes.rb最后的测试是这样的:

class ::Integer
  def even?
    (self % 2) == 0
  end
end

def test_even_existing_built_in_classes_can_be_reopened
  assert_equal true, 1.even?
  assert_equal false, 2.even?
end
Run Code Online (Sandbox Code Playgroud)

似乎def even?没有做任何事情; 如果我改变方法,它似乎不起作用:

class ::Integer
  def even?
    (self % 2) != 0
  end
end
Run Code Online (Sandbox Code Playgroud)

测试仍然成功.

我认为这是因为even已经在Ruby中定义了.那是对的吗?为什么会这样?

And*_*all 7

Ruby核心并不特别,问题在于even?这里不是来自Integer它,它来自于Fixnum.而且由于Fixnum1祖先比整数低,重新定义它Integer没有任何影响,因为从来没有被调用.

重新定义的Fixnum工作正常:

1.even?  #=> false
class Fixnum; def even?; true; end end
1.even?  #=> true
Run Code Online (Sandbox Code Playgroud)

而且,作为参考,这里1是祖先:

1.class.ancestors  #=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)

你可以告诉even?来自Fixnum通过获取一个Method对象,然后它的owner:

1.method(:even?).owner  #=> Fixnum
1.method(:ceil).owner   #=> Integer
Run Code Online (Sandbox Code Playgroud)