如果我想检查是否定义了具有给定名称的方法,哪个更好用,respond_to?
或defined?
?
从效率的角度来看,可能存在使用defined?
的论据,因为defined?
是内置关键字,而respond_to?
是一种方法,因此前者可能要快点但另一方面,在已知要检查的表达式是一种简单方法的情况下,defined?
需要解析整个表达式,与使用respond_to?
相比,这可能是一个缺点。 ,只需要接受参数作为方法名称。
哪个更好?是否应考虑效率以外的其他因素?
答案 0 :(得分:7)
如果我想检查是否定义了具有给定名称的方法,哪个更好用,
respond_to?
或defined?
?
都不是。使用Module#method_defined?
这不是一个真正的问题,而是更好的"使用:Object#respond_to?
方法和defined?
一元前缀运算符(尽管名称!)都不会检查方法是否定义:它们都是检查接收方是否响应 消息,这是完全不同的事情。
只有Module#method_defined?
才会实际检查方法是否已定义:
class Foo
def method_missing(*) end
def respond_to_missing?(*) true end
end
foo = Foo.new
defined? foo.bar
#=> 'method'
foo.respond_to?(:bar)
#=> true
Foo.method_defined?(:bar)
#=> false
答案 1 :(得分:0)
我的简短回答是我要么说。但是,Module#method_defined?
可能不适用于大多数情况。
这完全取决于您想知道什么。这是一个很长的答案,解释了目的。
我想最受欢迎的目的是Duck-typing,
即检查对象是否对具有特定名称的方法进行响应,如果响应,则不必理会对象实际上是什么类,或者不在内部实现方法的方式。在这种情况下,Object#respond_to?
(我认为)是为此设计的确切方法(如方法名称所示)。的确(如@JörgW Mittag指出的),如果在其类中重新定义Object#respond_to_missing?,则结果可能会改变。但是,这就是respond_to_missing?
的全部目的-将方法注册为有效-例如,请参见Ruby核心开发人员Marc-André的(旧)博客文章“ Method_missing, Politely”进行澄清。< / p>
另一种传统方法(自Ruby 1起)是使用Ruby内置的defined?
。 This past answer改为“在Ruby中,如何检查方法“ foo =()”是否已定义?”解释了defined?
特有的潜在有用案例,即告诉它是否为赋值。为了检查某个方法是否存在,在大多数(或所有?)情况下,defined?
的工作方式与Object#respond_to?
相似,只是它返回String对象或 nil 而不是布尔值。我会说这取决于个人喜好;但是,我在总体上赞成Object#respond_to?
,因为它显然更具体并且易于阅读,并且实际键入的潜在麻烦(如忘记为defined?
加上一对括号)的可能性较小。
或者,要检查对象的类是否具有在其自身之一,其超类和包含的模块之一中名称明确定义的方法,请使用Module#method_defined?。具体来说,此方法将忽略respond_to_missing?
,这意味着实际上忽略了任何使用BasicObject#method_missing的元编程(例如ActiveRecord of Rails广泛使用的元编程)。
此外,从Ruby 2.6.5开始,此Module#method_defined?
会忽略refinements,也就是说,using
引入的模块方法被视为未定义,与Object#respond_to?
和内置defined?
相比,两者都认为已定义了这些 refine-d 方法。
更原始的方法是使用obj.methods.include?(:bar)
之类的Object#methods来检查公共方法和受保护方法。这种方式的优点是,您可以通过指定参数true来排除对象类所包含的模块中的方法,例如obj.methods(false).include?(:bar)
。另外,如果需要,您可以使用Object#private_methods
,Object#protected_methods
,Object#public_method
进行更好的区分。它们都考虑了Object#respond_to_missing?。
另一种注释私有方法,包括内置的功能(也称为Kernel方法)。
Object#respond_to?默认情况下不会响应私有方法,除非第二个参数的值为true(请参阅上一个问题“ How to check if private method is defined in ruby”)。为此,请根据您要检查的内容来使用self.respond_to?(:bar, true)
或self.class.private_method_defined?(:bar)
之类的bar
或Module#private_method_defined?。
总结一下,检查称为obj.respond_to?(:bar)
()的方法,请
defined?(obj.bar)
(Object#respond_to?)进行鸭类检查obj.class.method_defined?(:bar)
(内置defined?)obj.methods(true).include?(:bar)
(Module#method_defined?)用于文字定义检查,不包括细化