如何调用哈希值的方法?
以前,我询问了一种在给定条件下执行方法的巧妙方法 “ Ruby是一种在条件上执行函数的聪明方法 。”
然而,解决方案和响应时间很长,在实现时,拥有lambda的哈希很快就会变得难看。 所以我开始尝试。
以下代码有效:
def a() puts "hello world" end some_hash = { 0 => a() } some_hash[0]
但是,如果我将它包装在一个类中它停止工作:
class A @a = { 0 => a()} def a() puts "hello world" end def b() @a[0] end end d = A.new() db()
我不明白为什么它应该停止工作,任何人都可以建议如何使它工作?
该代码不起作用。 它在添加到散列时执行a
,而不是从散列中检索它(在irb中尝试)。
它在类中不起作用,因为没有在类上定义的方法(最终在实例上定义方法a
。
尝试实际使用像lambda一样
{0 => lambda { puts "hello world" }}
代替
首先,你没有在哈希中放入lambda。 你将调用a()
的结果放在当前上下文中。
鉴于此信息,请考虑您class级中的代码含义。 类定义的上下文是类。 因此,您定义一个名为a
的实例方法,并将类实例变量分配给包含在当前上下文中调用a
的结果的哈希。 当前上下文是类A,而类A没有名为a
的类方法,因此您尝试将不存在的方法的结果放在那里。 然后在实例方法b
,您尝试访问名为@a
的实例变量 – 但没有一个。 类上下文中定义的@a
属于类本身,而不属于任何特定实例。
首先,如果你想要一个lambda,你需要制作一个lambda。 其次,您需要清楚类和该类的实例之间的区别。
如果要在某些条件下创建要调用的方法名称列表,可以这样做:
class A def self.conditions() { 0 => :a } end def a puts "Hello!" end def b(arg) send self.class.conditions[arg] end end
这将条件哈希定义为类的方法(使其易于访问),并且哈希仅包含要调用的方法的名称,而不是lambda或类似的东西。 所以当你调用b(0)
,它会自己发送包含在A.conditions [0]中的消息,这是a
。
table = { :a => 'test', :b => 12, :c => lambda { "Hallo" }, :d => def print(); "Hallo in test"; end } puts table[:a] puts table[:b] puts table[:c].call puts table[:d].send( :print )
如果你真的只想要这样的东西,为什么不将所有方法包装在类中:
# a container to store all your methods you want to use a hash to access class MethodHash alias [] send def one puts "I'm one" end def two puts "I'm two" end end x = MethodHash.new x[:one] # prints "I'm one" x.two # prints "I'm one"
或者,使用你的例子:
# a general purpose object that transforms a hash into calls on methods of some given object class DelegateHash def initialize(target, method_hash) @target = target @method_hash = method_hash.dup end def [](k) @target.send(@method_hash[k]) end end class A def initialize @a = DelegateHash.new(self, { 0 => :a }) end def a() puts "hello world" end def b() @a[0] end end x = A.new xa #=> prints "hello world" xb #=> prints "hello world"
您所做的另一个基本错误是您在任何实例方法之外初始化@a
– 只是在A
的定义内部。 这是禁忌的重要时刻,因为它不起作用。 请记住,在ruby中,一切都是对象,包括类, @
前缀表示当前任何对象的实例变量。 在实例方法定义中, self
是类的实例。 但除此之外,就在类定义中, self
是类对象 – 所以你为类对象A
定义了一个名为@a
的实例变量, A
的所有实例都不能直接进入。
Ruby确实有这种行为的原因(如果你知道你正在做什么,类实例变量可以非常方便),但这是一种更高级的技术。
简而言之,只在initialize
方法中初始化实例变量。
好吧,你class级的第一行调用一个尚不存在的方法。 在加载整个类之后它甚至不会存在,因为这将是对类方法的调用,并且您只定义了实例方法。
还要记住,{0 => a()}将调用方法a(),而不是创建方法a()的引用。 如果你想在那里放一个直到以后才进行评估的函数,你必须使用某种Lambda。
我很擅长在Ruby中使用回调,这就是我用自己的例子解释它的方法:
require 'logger' log = Logger.new('/var/tmp/log.out') def callit(severity, msg, myproc) myproc.call(sev, msg) end lookup_severity = {} lookup_severity['info'] = Proc.new { |x| log.info(x) } lookup_severity['debug'] = Proc.new { |x| log.debug(x) } logit = Proc.new { |x,y| lookup_sev[x].call(y) } callit('info', "check4", logit) callit('debug', "check5", logit)
a = – >(string =“没有字符串传递”)
把字符串
结束
some_hash = {0 => a}
some_hash [0] .call(“Hello World”)
some_hash [0] []