何时使用undef_method,何时使用remove_method?

And*_*imm 16 ruby reflection methods metaprogramming

我想重新定义一个方法,但避免与之相关的警告.我应该使用undef_method或remove_method这样做吗?

(是的,重新定义方法有点hacky.我这样做是因为我在运行单元测试时有一些我想要使用的memoization,但是当程序本身运行时却没有.)

mu *_*ort 22

精细手册:

undef_method(symbol)→self

阻止当前类响应对指定方法的调用.与此对比remove_method,从特定类中删除方法; Ruby仍将搜索超类和混合模块以寻找可能的接收器.

所以remove_method这样:

class CC < C
  remove_method :m
end
Run Code Online (Sandbox Code Playgroud)

基本上与此相反:

class CC < C
  def m
  end
end
Run Code Online (Sandbox Code Playgroud)

def m添加方法m的类,remove_method :m删除m.但是,如果超类有一个m方法,那么仍然会使用它.

undef_method,OTOH,更像这样:

class CC < C
  def m
    raise 'No, you cannot do that.'
  end
end
Run Code Online (Sandbox Code Playgroud)

所以undef_method实际上并没有删除该方法,它用一个特殊的内部标志替换该方法,如果你试图调用该方法,会导致Ruby抱怨.

听起来你正在尝试替换现有的方法,替换在语义上与删除后跟添加相同,所以remove_method可能更合适.但是,如果你想要偏执并确保替换方法到位,那么undef_method将是有用的; 或者,如果由于某种原因你需要在一个地方删除该方法并将其添加到另一个地方undef_method,至少会告诉你,你只做了一半的工作,而remove_method要么留给你超级类的实现(和可能的奇怪的错误)或相当令人困惑NoMethodError.


Ram*_*are 6

您可以通过两种简单的方式删除方法。激烈的

Module#undef_method( ) 
Run Code Online (Sandbox Code Playgroud)

删除所有方法,包括继承的方法。善良的人

Module#remove_method( ) 
Run Code Online (Sandbox Code Playgroud)

从接收器中删除方法,但它会单独保留继承的方法。

请参阅下面的 2 个简单示例 -

示例 1 使用undef_method

class A 
    def x
        puts "x from A class"
    end
end

class B < A
    def x
        puts "x from B Class"
    end
    undef_method :x
end

obj = B.new
obj.x
Run Code Online (Sandbox Code Playgroud)

结果 - main.rb:15:in ': undefined methodx' for # (NoMethodError)

示例 2 使用remove_method

class A 
    def x
        puts "x from A class"
    end
end

class B < A
    def x
        puts "x from B Class"
    end
    remove_method :x
end

obj = B.new
obj.x
Run Code Online (Sandbox Code Playgroud)

结果 - $ruby main.rb

x 来自 A 类