如何获得对某种方法的参考?
问题描述:
是否有可能在Ruby中获得一个对象的方法的引用(我想知道这是否可以在没有特效/ lambda表达式来完成),例如,考虑下面的代码:如何获得对某种方法的参考?
class X
def initialize
@map = {}
setup_map
end
private
def setup_map
# @map["a"] = get reference to a method
# @map["b"] = get reference to b method
# @map["c"] = get referebce to c method
end
public
def call(a)
@map["a"](a) if a > 10
@map["b"](a) if a > 20
@map["c"](a) if a > 30
end
def a(arg)
puts "a was called with #{arg}"
end
def b(arg)
puts "b was called with #{arg}"
end
def c(arg)
puts "c was called with #{arg}"
end
end
是它可能做这样的事情?我想避免procs/lambdas,因为我想通过继承来改变A,B,C的行为。
答
你想Object#method
:
---------------------------------------------------------- Object#method
obj.method(sym) => method
------------------------------------------------------------------------
Looks up the named method as a receiver in obj, returning a Method
object (or raising NameError). The Method object acts as a closure
in obj's object instance, so instance variables and the value of
self remain available.
class Demo
def initialize(n)
@iv = n
end
def hello()
"Hello, @iv = #{@iv}"
end
end
k = Demo.new(99)
m = k.method(:hello)
m.call #=> "Hello, @iv = 99"
l = Demo.new('Fred')
m = l.method("hello")
m.call #=> "Hello, @iv = Fred"
现在你的代码变成:
private
def setup_map
@map = {
'a' => method(:a),
'b' => method(:b),
'c' => method(:c)
}
# or, more succinctly
# @map = Hash.new { |_map,name| _map[name] = method(name.to_sym) }
end
public
def call(arg)
@map["a"][arg] if arg > 10
@map["b"][arg] if arg > 20
@map["c"][arg] if arg > 30
end
答
你可以用lambda表达式做到这一点,同时保持更改子类行为的能力:
class X
def initialize
@map = {}
setup_map
end
private
def setup_map
@map["a"] = lambda { |a| a(a) }
@map["b"] = lambda { |a| b(a) }
@map["c"] = lambda { |a| c(a) }
end
public
def call(a)
@map["a"].call(a) if a > 10
@map["b"].call(a) if a > 20
@map["c"].call(a) if a > 30
end
def a(arg)
puts "a was called with #{arg}"
end
def b(arg)
puts "b was called with #{arg}"
end
def c(arg)
puts "c was called with #{arg}"
end
end
答
Ruby方法不是第一类对象;它通过消息传递实现OO。
class X
def call(a)
self.send(:a, a) if a > 10
self.send(:b, a) if a > 20
self.send(:c, a) if a > 30
end
def a(arg)
puts "a was called with #{arg}"
end
def b(arg)
puts "b was called with #{arg}"
end
def c(arg)
puts "c was called with #{arg}"
end
end
,或直接打电话给他们:
def call(a)
self.a(a) if a > 10
self.b(a) if a > 20
self.c(a) if a > 30
end
+0
这是一个简单的例子。对于我需要编写的类,我将有大约20-30个方法来检查。如果支票不会很时尚,对吧? – Geo 2009-01-27 21:11:35
答
你可以得到的一个参考方法由object.method(:method_name)
。
例如:获得对system
方法的参考。
m = self.method(:system)
m.call('ls)
This Works!但是,没有办法获得实际的方法参考吗? – Geo 2009-01-27 21:03:26
你可以做的最好的是instance.methods,并给出了一个字符串数组。 – Samuel 2009-01-27 21:17:53