'respond_to?' 对比 'defined?'
'respond_to?' versus 'defined?'
如果我想检查是否定义了具有给定名称的方法,使用respond_to?
或defined?
?
哪个更好
从效率的角度来看,使用defined?
是有争议的,因为defined?
是内置关键字,而respond_to?
是方法,因此前者可能更快。但另一方面,在已知要检查的表达式是一个简单方法的情况下,defined?
需要解析整个表达式,这与使用 respond_to?
相比可能是一个缺点,它只需要接受参数作为方法名称。
哪个更好?除了效率之外,还有其他需要考虑的地方吗?
If I want to check whether a method with a given name is defined, which is better to use, respond_to?
, or defined?
?
都没有。使用 Module#method_defined?
使用 "better" 并不是真正的问题: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
我的简短回答是我会说。但是,Module#method_defined?
可能不适合大多数情况。
这完全取决于您想知道什么。这是一个很长的答案,解释了目的。
我猜最受欢迎的用途是 Duck-typing,
即检查对象 是否响应 具有特定名称的方法,如果响应,则您不关心它实际上是什么 class 或 where/how 该方法是内部实现的。在这种情况下,Object#respond_to?
是(我认为)为它设计的确切方法(正如方法名称所暗示的那样)。确实(正如@Jörg W Mittag 指出的那样),如果 Object#respond_to_missing? is redefined in its class. However, that is the whole purpose of respond_to_missing?
— to register methods as valid — see, for example, the (old) blog post "Method_missing, Politely" 由 Ruby 核心开发人员 Marc-André 澄清,结果可能会改变。
另一种传统方法(自 Ruby 1 起)是使用 Ruby 内置 defined?
. This past answer 到 "In Ruby, how do I check if method “foo=()” is defined?" 解释了一个可能有用的案例,具体与 defined?
,即判断是否赋值。为了检查方法是否存在,defined?
在大多数(或所有?)情况下类似于 Object#respond_to?
,除了它 returns 一个 String 对象或 nil 而不是布尔值。我会说这取决于个人喜好;但是,总的来说,我赞成 Object#respond_to?
,因为它显然更具体,因此可读性更强,而且实际打字的潜在麻烦,例如忘记 defined?
的一对括号的可能性较小。
或者,要检查对象的 class 是否在其自身、其超classes 和包含的模块之一中明确定义了方法,请使用 Module#method_defined?. Specifically, this method ignores respond_to_missing?
, which means in practice any meta programming with BasicObject#method_missing (例如,Rails 的 ActiveRecord 广泛使用)被忽略。
此外,从 Ruby 2.6.5 开始,此 Module#method_defined?
将忽略定义的 refinements, that is, the module methods introduced by using
are regarded not defined, in contrast of Object#respond_to?
and built-in defined?
, both of which regards those refine-d 方法。
一种更原始(?)的方法是使用Object#methods like obj.methods.include?(:bar)
to check public and protected methods. An advantage of this way is, you can exclude the methods in the modules included in the class of the object, by specifying the argument true, like obj.methods(false).include?(:bar)
. Also, you can make a finer distinguishment with Object#private_methods
, Object#protected_methods
, Object#public_method
instead, if need be. They all take into account Object#respond_to_missing?。
关于私有方法的更多评论,其中包括内置 函数 (又名 Kernel 方法)。
Object#respond_to? 默认不响应私有方法,除非第二个参数为真(见上一个问题“”)。为此,请使用 self.respond_to?(:bar, true)
或 Module#private_method_defined?,如 self.class.private_method_defined?(:bar)
,具体取决于您要检查的内容。
总而言之,要检查名为 bar
() 的方法,请执行
obj.respond_to?(:bar)
(Object#respond_to?) 用于鸭子类型检查
defined?(obj.bar)
(内置`defined?)用于一般用途
obj.class.method_defined?(:bar)
(Module#method_defined?) 用于文字定义检查,不包括细化
obj.methods(true).include?(:bar)
(Object#methods) 获取方法列表并求值(这里可以通过指定false来排除包含的模块)
如果我想检查是否定义了具有给定名称的方法,使用respond_to?
或defined?
?
从效率的角度来看,使用defined?
是有争议的,因为defined?
是内置关键字,而respond_to?
是方法,因此前者可能更快。但另一方面,在已知要检查的表达式是一个简单方法的情况下,defined?
需要解析整个表达式,这与使用 respond_to?
相比可能是一个缺点,它只需要接受参数作为方法名称。
哪个更好?除了效率之外,还有其他需要考虑的地方吗?
If I want to check whether a method with a given name is defined, which is better to use,
respond_to?
, ordefined?
?
都没有。使用 Module#method_defined?
使用 "better" 并不是真正的问题: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
我的简短回答是我会说。但是,Module#method_defined?
可能不适合大多数情况。
这完全取决于您想知道什么。这是一个很长的答案,解释了目的。
我猜最受欢迎的用途是 Duck-typing,
即检查对象 是否响应 具有特定名称的方法,如果响应,则您不关心它实际上是什么 class 或 where/how 该方法是内部实现的。在这种情况下,Object#respond_to?
是(我认为)为它设计的确切方法(正如方法名称所暗示的那样)。确实(正如@Jörg W Mittag 指出的那样),如果 Object#respond_to_missing? is redefined in its class. However, that is the whole purpose of respond_to_missing?
— to register methods as valid — see, for example, the (old) blog post "Method_missing, Politely" 由 Ruby 核心开发人员 Marc-André 澄清,结果可能会改变。
另一种传统方法(自 Ruby 1 起)是使用 Ruby 内置 defined?
. This past answer 到 "In Ruby, how do I check if method “foo=()” is defined?" 解释了一个可能有用的案例,具体与 defined?
,即判断是否赋值。为了检查方法是否存在,defined?
在大多数(或所有?)情况下类似于 Object#respond_to?
,除了它 returns 一个 String 对象或 nil 而不是布尔值。我会说这取决于个人喜好;但是,总的来说,我赞成 Object#respond_to?
,因为它显然更具体,因此可读性更强,而且实际打字的潜在麻烦,例如忘记 defined?
的一对括号的可能性较小。
或者,要检查对象的 class 是否在其自身、其超classes 和包含的模块之一中明确定义了方法,请使用 Module#method_defined?. Specifically, this method ignores respond_to_missing?
, which means in practice any meta programming with BasicObject#method_missing (例如,Rails 的 ActiveRecord 广泛使用)被忽略。
此外,从 Ruby 2.6.5 开始,此 Module#method_defined?
将忽略定义的 refinements, that is, the module methods introduced by using
are regarded not defined, in contrast of Object#respond_to?
and built-in defined?
, both of which regards those refine-d 方法。
一种更原始(?)的方法是使用Object#methods like obj.methods.include?(:bar)
to check public and protected methods. An advantage of this way is, you can exclude the methods in the modules included in the class of the object, by specifying the argument true, like obj.methods(false).include?(:bar)
. Also, you can make a finer distinguishment with Object#private_methods
, Object#protected_methods
, Object#public_method
instead, if need be. They all take into account Object#respond_to_missing?。
关于私有方法的更多评论,其中包括内置 函数 (又名 Kernel 方法)。
Object#respond_to? 默认不响应私有方法,除非第二个参数为真(见上一个问题“self.respond_to?(:bar, true)
或 Module#private_method_defined?,如 self.class.private_method_defined?(:bar)
,具体取决于您要检查的内容。
总而言之,要检查名为 bar
() 的方法,请执行
obj.respond_to?(:bar)
(Object#respond_to?) 用于鸭子类型检查defined?(obj.bar)
(内置`defined?)用于一般用途obj.class.method_defined?(:bar)
(Module#method_defined?) 用于文字定义检查,不包括细化obj.methods(true).include?(:bar)
(Object#methods) 获取方法列表并求值(这里可以通过指定false来排除包含的模块)