如何调用哈希值的方法?

时间:2009-07-01 22:03:32

标签: ruby hash methods call

在此之前,我询问了一种在给定条件“Ruby a clever way to execute a function on a condition”上执行方法的聪明方法。

解决方案和响应时间很长,但是,在实现时,拥有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()

我不明白为什么它应该停止工作,有人可以建议如何让它工作吗?

7 个答案:

答案 0 :(得分:7)

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

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

尝试使用像

这样的lambdas
{0 => lambda { puts "hello world" }} 

代替

答案 1 :(得分:5)

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

鉴于此信息,请考虑您班级中的代码含义。类定义的上下文是类。因此,您定义一个名为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)时,send本身就是A.conditions [0]中包含的消息,即a

答案 2 :(得分:3)

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 )

答案 3 :(得分:2)

如果你真的只想要这样的东西, 为什么不将所有方法包装在类中:

# 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是类对象 - 所以你定义了 类对象@a的名为A的实例变量,A的任何实例都不能直接进入。

Ruby确实有这种行为的原因(如果你知道什么,类实例变量可以非常方便 你正在做,但这是一种更先进的技术。

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

答案 4 :(得分:1)

嗯,你班级的第一行调用一个尚不存在的方法。在加载整个类之后它甚至不会存在,因为这将是对类方法的调用,并且您只定义了实例方法。

另请注意{0 => a()}将调用方法a(),而不是创建方法a()的引用。如果你想在那里放一个直到以后才进行评估的函数,你必须使用某种Lambda。

答案 5 :(得分:1)

我很擅长在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)

答案 6 :(得分:0)

  

a = - >(string =“没有字符串传递”)做

     

put string

     

     

some_hash = {0 => a}

     

some_hash [0] .call(“Hello World”)

     

some_hash [0] []