我正在学习Ruby,我不清楚:*表示注入(:*)

时间:2015-05-20 17:37:21

标签: ruby

我正在编写一种计算数字阶乘的方法,我在搜索中发现了类似的东西。

def factorial(number)
  (1..number).inject(:*) || 1
end

它有效并且我理解注入函数正在做什么,但我不清楚(:\*)部分真正意味着什么。

我知道它必须是写{|num, prod| num*prod}的速记版本,但我希望有一个明确的解释。谢谢!

4 个答案:

答案 0 :(得分:2)

:*只是*执行方法inject的方法名称。如果您查看inject http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-inject

的文档

它声明

  

如果指定了符号,则集合中的每个元素都将传递给命名的备忘录方法。在任何一种情况下,结果都将成为备忘录的新值。在迭代结束时,memo的最终值是方法的返回值。

因此inject { |memo, obj| block }

以下是相同的

ary = [1,2,3]
ary.inject(:*)
#=> 6
ary.inject { |memo, obj| memo.*(obj) }
#=> 6

答案 1 :(得分:2)

简短说明

:*是一个符号。符号是不可变的字符串。 :*"*"类似,只是它不可变。

在ruby中,乘法也是一种方法调用。它相当于调用第一个乘数的.*(second)方法,第二个乘数作为参数。实际上,您可以输入3.*(4)而不是3*4。就红宝石而言,3*4只是语法糖。

可以通过public_send符号消息调用对象来调用ruby中的方法调用。 3.public_send(:*, 4)也可以像3*4一样工作。

inject的参数被解释为应该是什么类型的消息public_senT,也就是说,应该从inject方法的内部调用什么方法。

更长的解释

你可以想到

[ 1, 2, 3, 4 ].inject(:*)

注射' *'在inject上调用的每个可枚举对象的每个相邻对之间:

[ 1, 2, 3, 4 ].inject(:*) == 1 * 2 * 3 * 4

当然1 * 2 * 3 * 4相当于从左到右,并在您的正在运行的计数上应用:*以及下一个数字以获得下一个计数,然后返回最终结果。

module Enumerable
  def inject_asterisk
     tally = first
     rest = slice(1, length - 1)
     rest.each  do |next_num|
       tally = tally * next_num
     end
     return tally
  end
end
[2, 3, 5].inject_asterisk #=> 30

您可以通过组合tallynext_number的操作来概括这一点,以获得您的下一个tally参数函数。 ruby中的块基本上用作始终具有保留点的参数函数。

module Enumerable
  def inject_block(&block)
     tally = first
     rest = slice(1, length - 1)
     rest.each  do |next_num|
       tally = block.call(tally, next_num)
     end
     return tally
  end
end
[2, 3, 5].inject_block {|tally, next_num| tally + next_num } #=> 10

如果您的区块总是具有

形式
{|tally, next_num| tally.method_of_tally(next_num) }

就像这种情况一样(记住tally + next_num< ==> tally.+(next_num)< ==> tally.public_send(:+,next_num),您可以决定只传递:method_of_tally作为论据并暗示阻止。

 module Enumerable
  def my_inject(method_of_tally_symbol, &block)

     if method_of_tally_symbol
        block = Proc.new  { |tally, next_num| 
               tally.public_send(method_of_tally_symbol, next_num) 
               }
     end

     tally = first
     rest = slice(1, length - 1)
     rest.each  do |next_num|
       tally = block.call(tally, next_num)
     end
     return tally
  end
end
[2, 3, 5].my_inject(:+) #=> 10

将重复的模式提取到可重用的组件中是为了让您不必输入任何内容。

答案 2 :(得分:0)

这意味着array.map { |e| e.join } ,这是一个捷径。通常你会写一些类似

的东西
array.map(&:join)

用符号表示proc,速记就是

inject

reduce&相似,但在这些情况下您不需要numbers

例如,如果您有一组名为numbers.inject(&:+)

的数字

要对数字求和,您可以

numbers.inject(:+)

或者你可以不用&符号

OrderedDict

答案 3 :(得分:0)

http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-inject

Inject是一个枚举方法,它使用符号(如您的情况)或块(如您提议的缩写)组合所述枚举的元素。

例如:

sort相当于(5..10).reduce(:*)

相关问题