Ruby 如何调用散列值的方法?

Ruby 如何调用散列值的方法?,ruby,hash,methods,call,Ruby,Hash,Methods,Call,以前,我问过一种在给定条件下执行方法的聪明方法 解决方案和响应时间都很好,不过在实现时,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

以前,我问过一种在给定条件下执行方法的聪明方法

解决方案和响应时间都很好,不过在实现时,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()

d.b()

我不明白为什么它会停止工作,有人能建议如何使它工作吗?

好吧,你的类的第一行调用了一个还不存在的方法。但是,在加载整个类之后,它甚至不存在,因为这将是对类方法的调用,而您只定义了实例方法


还要记住,{0=>a()}将调用方法a(),而不是创建对方法a()的引用。如果你想把一个函数放在那里,直到以后才被计算,你就必须使用某种Lambda。

那代码不起作用。它在添加到散列时执行
a
,而不是在从散列检索时执行(在irb中尝试)

它在类中不起作用,因为类上没有定义
a
方法(您最终在实例上定义了方法
a

试着像这样使用lambdas

{0 => lambda { puts "hello world" }} 

相反

首先,您没有将lambda放入哈希中,而是将调用
a()
的结果放入当前上下文中

给定此信息,考虑类中的代码意味着什么。类定义的上下文是类。因此,定义一个实例方法,称为“代码> A<代码>,并将类实例变量赋给包含当前代码中的调用<代码> A<代码>的结果的哈希。当前上下文是A类和A类DOE。s没有名为

a
的类方法,因此您尝试将不存在的方法的结果放在那里。然后在实例方法
b
中,您尝试访问名为
@a
的实例变量,但没有。在类上下文中定义的
@a
属于类本身,而不是任何特定的实例e

所以首先,如果你想要一个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

如果你真的只是想把这类东西弄得漂亮一点, 为什么不将所有方法封装在一个类中,如下所示:

# 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
x.a #=> prints "hello world"
x.b #=> prints "hello world"
您犯的另一个基本错误是在任何实例方法之外初始化了
@a
- 只需了解
A
的定义就行了。这是一个非常重要的时刻不,不,因为它根本不起作用。 记住,在ruby中,一切都是对象,包括类,
@
前缀表示实例 当前为self的任何对象的变量。在实例方法定义中,
self
是一个实例 但除此之外,就在类定义的内部,
self
是类对象,所以您定义了 类对象
a
的名为
@a
的实例变量,
a
的任何实例都不能直接访问该变量

Ruby确实有这种行为的原因(如果您知道 但这是一种更先进的技术

简而言之,仅在
initialize
方法中初始化实例变量

a=->(string=“无字符串传递”)是否执行

放线

结束

some_hash={0=>a}

某些\u散列[0]。调用(“Hello World”)

一些散列[0][]


我对在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={0=>lambda{a.new.a()}然后你必须用@a[0]来调用它.call这正是我试图避免的。我放在lambda中的代码可能会有点混乱,我会在散列中包含大约15个元素。这会使代码有点混乱。@Peter:lambda中的代码比方法中的代码更混乱吗?然后将方法名称作为符号传递,并使用send或Symbol#to_proc。@Chuck它会是相同的,但将代码包装在方法中,然后在哈希中引用它们似乎是一个更漂亮的解决方案。您是否考虑过创建一个类方法,该方法可以接受一个块并将其作为lambda添加到哈希中,然后根据需要在类主体中使用它。
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)