2

之前,我问过一种在给定条件下执行方法的聪明方法“Ruby a quiet way to execute a function on a condition ”。

解决方案和响应时间都很棒,但是,在实施时,有一个 lambdas 散列很快就会变得丑陋。于是我开始尝试。

以下代码有效:

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()

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

4

7 回答 7

7

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

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

尝试实际使用像

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

反而

于 2009-07-01T22:13:53.823 回答
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.

于 2009-07-01T22:20:05.620 回答
3

如果你真的只是想美化这种东西,为什么不将所有方法包装在一个类中,如下所示:

# 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是一个类的实例。但除此之外,就在类定义内部,是类对象 - 所以你定义了一个以类 objectself命名的实例变量,没有一个实例可以直接访问。@aAA

Ruby 确实有这种行为的原因(如果您知道自己在做什么,类实例变量会非常方便),但这是一种更高级的技术。

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

于 2009-07-02T07:48:12.763 回答
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 )
于 2012-06-20T03:29:52.403 回答
1

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

另请记住,{0 => a()} 将调用方法 a(),而不是创建对方法 a() 的引用。如果您想在其中放置一个直到稍后才被评估的函数,您必须使用某种 Lambda。

于 2009-07-01T22:11:01.300 回答
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)
于 2012-08-22T10:06:48.263 回答
0

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

放字符串

结尾

some_hash = { 0 => a }

some_hash[0].call("Hello World")

some_hash[0][]

于 2010-10-25T21:34:59.410 回答