【问题标题】:What are :+ and &:+ in Ruby?Ruby 中的 :+ 和 &:+ 是什么?
【发布时间】:2010-04-23 07:59:42
【问题描述】:

我已经看过好几次了,但我不知道如何使用它们。镐说这些是特殊的快捷方式,但我找不到语法描述。

我曾在这种情况下见过他们:

[1,2,3].inject(:+)

例如计算总和。

【问题讨论】:

  • 仅供参考,你的例子是错误的,它应该是[1,2,3].inject(&:+)
  • 我仔细检查过,[1,2,3].inject(:+) 确实有效。为什么?
  • 那么它一定是inject 方法的一个特性。 inject(:+) 不是 Symbol#to_proc,:+ 在 ruby​​ 语言中没有特殊含义——它只是一个符号。
  • 是的,在 ruby​​ 1.8.7+ 中,当没有给出块时,注入使用它的第一个参数作为方法名称(这比使用 Symbol#to_proc 或常规块快得多,顺便说一句)。

标签: ruby


【解决方案1】:

让我们从一个更简单的例子开始。 假设我们有一个字符串数组,我们想用大写字母:

['foo', 'bar', 'blah'].map { |e| e.upcase }
# => ['FOO', 'BAR', 'BLAH']

另外,您可以创建所谓的 Proc 对象(闭包):

block = proc { |e| e.upcase }
block.call("foo") # => "FOO"

您可以将这样的过程传递给具有 & 语法的方法:

block = proc { |e| e.upcase }
['foo', 'bar', 'blah'].map(&block)
# => ['FOO', 'BAR', 'BLAH']

这样做是在块上调用 to_proc,然后为每个块调用它:

some_object = Object.new
def some_object.to_proc
  proc { |e| e.upcase }
end

['foo', 'bar', 'blah'].map(&some_object)
# => ['FOO', 'BAR', 'BLAH']

现在,Rails 先给 Symbol 添加了 to_proc 方法,后来又被添加到了 ruby​​ 核心库中:

:whatever.to_proc # => proc { |e| e.whatever }

因此你可以这样做:

['foo', 'bar', 'blah'].map(&:upcase)
# => ['FOO', 'BAR', 'BLAH']

此外,Symbol#to_proc 更加智能,因为它实际上做了以下事情:

:whatever.to_proc # => proc { |obj, *args| obj.send(:whatever, *args) }

这意味着

[1, 2, 3].inject(&:+)

等于

[1, 2, 3].inject { |a, b| a + b }

【讨论】:

  • inject 也支持[1,2,3].inject(:+)(注意你不需要&)
  • 在这种情况下,它会检查一个对象是否传递了对它本身的调用 to_proc 。 def inject(obj, &block) block ||= obj.to_proc # ... end
  • 这不是 ruby​​ 对注入的定义。 inject 不调用 to_proc,它使用带有给定符号的 rb_funcall 作为方法的名称。参见 enum.c 中的 inject_op_i。
  • 好的,但是 &:+ 仍然会调用 to_proc。
  • &:+ 语法不是问题的情况下谈论太多。
【解决方案2】:

inject 接受一个符号作为参数,这个符号必须是方法或操作符的名称,本例为:+

所以[1,2,3].inject(:+) 将每个值传递给符号指定的方法,从而对数组中的所有元素求和。

来源:https://ruby-doc.org/core-2.5.1/Enumerable.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-15
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    • 2013-01-31
    • 2010-10-29
    相关资源
    最近更新 更多