Ruby:方法作为数组元素 - 它们如何工作?

时间:2012-12-19 09:12:23

标签: ruby

这可能不是你应该在家里尝试的东西,但由于某种原因,我试图在Ruby中创建一个方法数组。

我首先定义了两种方法。

irb(main):001:0> def test1
irb(main):002:1>   puts "test!"
irb(main):003:1> end
=> nil
irb(main):004:0> def test2
irb(main):005:1>   puts "test2!"
irb(main):006:1> end
=> nil

当您尝试将其放入实际数组时会发生奇怪的事情。它似乎运行两种方法。

irb(main):007:0> array = [test1, test2]
test!
test2!
=> [nil, nil]

之后,阵列是空的。

irb(main):008:0> puts array


=> nil

有人可以向我解释为什么它会运行这些方法吗?除此之外,整个练习严重需要一个驱魔人吗?

6 个答案:

答案 0 :(得分:21)

您在数组中存储的是调用方法的结果,而不是方法本身。

def test1
  puts "foo!"
end

def test2
  puts "bar!"
end

您可以存储对实际方法的引用,如下所示:

> arr = [method(:test1), method(:test2)]
# => [#<Method: Object#test1>, #<Method: Object#test2>] 

稍后,您可以调用这样的引用方法:

> arr.each {|m| m.call }
foo!
bar!

答案 1 :(得分:4)

@alestanis很好地解释了原因。如果你试图存储方法,那么你可以做Lars Haugseth所说的或者你可以做以下事情:

test1 = Proc.new { puts "test!" }
test2 = Proc.new { puts "test2!" }
a = [test1, test2]

这可能会使您的代码更具可读性。

这是一个irb run。

1.9.3p194 :009 > test1 = Proc.new { puts "test!" }
 => #<Proc:0x00000002798a90@(irb):9> 
1.9.3p194 :010 > test2 = Proc.new { puts "test2!" }
 => #<Proc:0x00000002792988@(irb):10> 
1.9.3p194 :011 > a = [test1, test2]
 => [#<Proc:0x00000002798a90@(irb):9>, #<Proc:0x00000002792988@(irb):10>] 

答案 2 :(得分:1)

如果你有一个square方法并且想要创建一个方形值为2和4的数组,你会写

array = [square(2), square(4)]

在这里你做的完全相同,除了你的测试方法没有返回任何东西,这就是为什么你的最终array似乎是空的(实际上,它包含[nil, nil])。

答案 3 :(得分:1)

您的数组永远不会包含除两个nil值之外的任何内容。我在评估时通过放置字符串来欺骗你。但是每个函数的返回值仍然是零。

答案 4 :(得分:1)

您的代码运行这两种方法,因为当您说“test1”和“test2”时,您实际上正在调用方法 - 括号对于ruby方法调用是可选的。

由于你的两个方法只包含一个返回nil的“puts”,你得到的数组只是一个包含两个nils的数组。

答案 5 :(得分:0)

这是我的两便士价值。基于已发布的解决方案,这是一个工作示例的示例。对于某些人来说可能比较方便的是它包含方法参数和self(在实例化时引用PromotionalRules类的实例)和符号数组的使用,这很简单 - 我得到了来自#send方法here上的Ruby文档。希望这有助于某人!

class PromotionalRules
  PROMOTIONS = [:lavender_heart_promotion, :ten_percent_discount]

  def apply_promotions total, basket
    @total = total

    if PROMOTIONS.count > 0
      PROMOTIONS.each { |promotion| @total = self.send promotion, @total, basket }
    end

    @total.round(2)
  end

  def lavender_heart_promotion total, basket
    if two_or_more_lavender_hearts? basket
      basket.map { |item| total -= 0.75 if item == 001 }
    end
    total
  end

  def two_or_more_lavender_hearts? basket
    n = 0
    basket.each do |item|
      n += 1 if item == 001
    end
    n >= 2
  end

  def ten_percent_discount total, *arg
    if total > 60.00
      total = total - total/10
    end
    total
  end
end

感谢大家的帮助。我喜欢编码的开源本质 - 当人们迭代彼此的解决方案时,线程会越来越好!