respond_to?
来检查对象是否有某个特定的方法。但是,针对一个类,我如何检查实例是否有某个特定的方法?
比如说,像这样:
Foo.new.respond_to?(:bar)
不过我觉得肯定有比实例化新实例更好的方法。
respond_to?
来检查对象是否有某个特定的方法。Foo.new.respond_to?(:bar)
不过我觉得肯定有比实例化新实例更好的方法。
我不知道为什么每个人都建议你使用instance_methods
和include?
,而method_defined?
就可以完成任务。
class Test
def hello; end
end
Test.method_defined? :hello #=> true
注意
如果你是从另一种面向对象语言转到 Ruby,或者你认为 method_defined
只是指你使用以下方式显式定义的方法:
def my_method
end
那么请阅读以下内容:
在 Ruby 中,模型上的属性(attribute)本质上也是一个方法。所以 method_defined?
不仅会对方法返回 true,也会对属性返回 true。
例如:
给定一个拥有字符串属性 first_name
的类的实例:
<instance>.first_name.class #=> String
<instance>.class.method_defined?(:first_name) #=> true
因为first_name
既是属性又是方法(并且是字符串类型的String)。
您可以如下使用method_defined?
:
String.method_defined? :upcase # => true
和其他人提出的instance_methods.include?
相比,这种方法更容易、便携和高效。
请记住,如果一个类动态地响应某些调用,例如通过重新定义respond_to?
或自Ruby 1.9.2以来通过定义respond_to_missing?
,那么你将不会知道。
instance.class.method_defined? :upcase
。 - user483040实际上,这种方法对于对象和类都不起作用。
而这种方法可以:
class TestClass
def methodName
end
end
所以根据提供的答案,这个方法可以正常工作:
TestClass.method_defined? :methodName # => TRUE
t = TestClass.new
t.method_defined? : methodName # => ERROR!
TestClass.methods.include? 'methodName' # => TRUE
对象:
t = TestClass.new
t.methods.include? 'methodName' # => TRUE
对于 "给定一个类,查看实例是否有方法(Ruby)" 的答案更好。显然 Ruby 内置了这个功能,但我不知道。无论如何,我的答案仅供参考。
Ruby 类响应 instance_methods
和 public_instance_methods
方法。在 Ruby 1.8 中,第一个方法会将所有实例方法名称列在一个字符串数组中,而第二个方法则将其限制为公共方法。最可能想要的是第二种行为,因为 respond_to?
默认也会将自己限制为公共方法。
Foo.public_instance_methods.include?('bar')
Foo.public_instance_methods.include?(:bar)
Module
以包括一种快捷方法。(将此分配给Module
而不是Class
可能会看起来有些奇怪,但由于这是instance_methods
方法存在的位置,最好保持与该模式一致。)class Module
def instance_respond_to?(method_name)
public_instance_methods.include?(method_name)
end
end
如果你想支持Ruby 1.8和Ruby 1.9,那么在这里添加搜索字符串和符号的逻辑将非常方便。
method_defined?
更好 :) - horseyguyFoo.instance_methods.include? :bar
来检查。class Foo
def self.fclass_method
end
def finstance_method
end
end
foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method]
foo_obj.class.instance_methods(false)
=> [:fclass_method]
如果你想检查一个对象是否能够响应一系列的方法,你可以这样做:
methods = [:valid?, :chase, :test]
def has_methods?(something, methods)
methods & something.methods == methods
end
方法 & something.methods
将两个具有共同/匹配元素的数组连接起来。something.methods 包含您要检查的所有方法,它将等于 methods。例如:
[1,2] & [1,2,3,4,5]
==> [1,2]
so
[1,2] & [1,2,3,4,5] == [1,2]
==> true
["my", "methods"]
,它将返回false。method_defined?
存在一些问题,可能不一致或其他原因,因此如果您使用Rails,最好使用attribute_method?(attribute)
中的某个内容。不确定这是否是最好的方法,但您始终可以尝试以下操作:
Foo.instance_methods.include? 'bar'
klass.instance_methods.include :method_name
或"method_name"
String.instance_methods(false).include? :freeze
这种方式时,虽然有至少一个优点,即参数中的 false 可以准确判断 String 类中是否定义了freeze
方法。在这种情况下,它会返回 false,因为freeze
方法是通过 String 继承自 Kernel 模块的,但是String.method_defined? :freeze
始终会返回 true,对于这个目的没什么帮助。 - ugoamethod_defined?
必须在类上使用(例如Array
),但你试图在实例上使用它(例如[]
)。 - horseyguy