Ruby: methods as array elements - how do they work?

时间:2022-11-28 15:24:55

This probably isn't something you should try at home, but for some reason or another I tried to create an array of methods in Ruby.

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

I started by defining two methods.

我开始定义两种方法。

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

The weird thing happens when you try to put it into an actual array. It seems to run both methods.

当你试图把它放到一个实际的数组中时会发生奇怪的事情。它似乎运行两种方法。

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

And afterwards, the array is empty.

然后,阵列是空的。

irb(main):008:0> puts array


=> nil

Can someone explain to me why it runs the methods? Other than that the whole excercise is seriously in need of an exorcist?

有人可以向我解释为什么它运行这些方法吗?除此之外,整个运动是否真的需要一个驱魔人?

6 个解决方案

#1


16  

What you're storing in your array is the result of calling your methods, not the methods themselves.

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

def test1
  puts "foo!"
end

def test2
  puts "bar!"
end

You can store references to the actual methods like this:

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

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

Later, you can call the referenced methods like this:

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

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

#2


3  

@alestanis explained the reason well. If you were trying to store the methods, then you can do what Lars Haugseth says or you could do the folllowing:

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

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

This may make your code much more readable.

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

Here is an irb run.

这是一个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>] 

#3


1  

Your array never contains anything else than two nil values. I tricks you by putting the strings when evaluating. But the return value of each function still is nil.

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

#4


1  

Your code runs the two methods because you're actually calling the methods when you say "test1" and "test2" - parentheses are optional for ruby method calls.

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

Since both of your methods just contain a "puts", which returns nil, your resulting array is just an array of two nils.

由于两个方法都只包含一个返回nil的“puts”,因此生成的数组只是一个包含两个nils的数组。

#5


1  

If you had a square method and wanted to create an array with the square values of 2 and 4, you would write

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

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

Here you are doing exactly the same thing, except that your test methods don't return anything and that's why your final array seems empty (actually, it contains [nil, nil]).

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

#6


0  

Here's my two-pennies worth. Building on the solutions already posted, this is an example of a working example. What might be handy for some here is that it includes method arguments and the use of self (which refers to the instance of the PromotionalRules class when it is instantiated) and the array of symbols, which is neat - I got that from the Ruby docs on the #send method here. Hope this helps someone!

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

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

Thanks to everyone for their help. I love the open-source nature of coding - threads just get better and better as people iterate over each other's solutions!

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

#1


16  

What you're storing in your array is the result of calling your methods, not the methods themselves.

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

def test1
  puts "foo!"
end

def test2
  puts "bar!"
end

You can store references to the actual methods like this:

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

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

Later, you can call the referenced methods like this:

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

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

#2


3  

@alestanis explained the reason well. If you were trying to store the methods, then you can do what Lars Haugseth says or you could do the folllowing:

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

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

This may make your code much more readable.

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

Here is an irb run.

这是一个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>] 

#3


1  

Your array never contains anything else than two nil values. I tricks you by putting the strings when evaluating. But the return value of each function still is nil.

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

#4


1  

Your code runs the two methods because you're actually calling the methods when you say "test1" and "test2" - parentheses are optional for ruby method calls.

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

Since both of your methods just contain a "puts", which returns nil, your resulting array is just an array of two nils.

由于两个方法都只包含一个返回nil的“puts”,因此生成的数组只是一个包含两个nils的数组。

#5


1  

If you had a square method and wanted to create an array with the square values of 2 and 4, you would write

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

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

Here you are doing exactly the same thing, except that your test methods don't return anything and that's why your final array seems empty (actually, it contains [nil, nil]).

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

#6


0  

Here's my two-pennies worth. Building on the solutions already posted, this is an example of a working example. What might be handy for some here is that it includes method arguments and the use of self (which refers to the instance of the PromotionalRules class when it is instantiated) and the array of symbols, which is neat - I got that from the Ruby docs on the #send method here. Hope this helps someone!

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

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

Thanks to everyone for their help. I love the open-source nature of coding - threads just get better and better as people iterate over each other's solutions!

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