一些简单的Ruby问题 - 迭代器,块和符号

Maj*_*ons 6 ruby

我的背景是PHP和C#,但我真的很想学习RoR.为此,我开始阅读官方文档.我对一些代码示例有一些疑问.

第一个是迭代器:

class Array
  def inject(n)
    each { |value| n = yield(n, value) }
    n
  end

  def sum
    inject(0) { |n, value| n + value }
  end

  def product
    inject(1) { |n, value| n * value }
  end
end
Run Code Online (Sandbox Code Playgroud)

我明白这yield意味着"在这里执行相关的块".扔我的是这|value| n =部分each.其他块对我来说更有意义,因为它们似乎模仿C#风格的lambdas:

public int sum(int n, int value)
{
    return Inject((n, value) => n + value);
}
Run Code Online (Sandbox Code Playgroud)

但第一个例子让我感到困惑.

另一个是符号.我什么时候想用它们?为什么我不能这样做:

class Example
  attr_reader @member

  # more code
end
Run Code Online (Sandbox Code Playgroud)

Mat*_*ira 3

injectorreduce方法中,n代表累加值;这意味着每次迭代的结果都会累积在n变量中。正如您的示例中所示,这可能是数组中元素的总和或乘积。

yield返回块的结果,该结果存储n在下一次迭代中并在下一次迭代中使用。这就是结果“累积”的原因。

a = [ 1, 2, 3 ]
a.sum  # inject(0) { |n, v| n + v }
# n == 0; n = 0 + 1
# n == 1; n = 1 + 2
# n == 3; n = 3 + 3
 => 6
Run Code Online (Sandbox Code Playgroud)

另外,要计算总和,您也可以编写a.reduce :+. 这适用于任何二元运算。如果你的方法被命名了symbol,那么写作a.reduce :symbol就和写作一样a.reduce { |n, v| n.symbol v }

attr和公司实际上都是方法。在幕后,他们动态地为您定义方法。它使用您传递的符号来计算实例变量和方法的名称。:member结果是@member实例变量以及membermember =方法。

不能写的原因attr_reader @member@member它本身不是对象,也不能转换为符号;它实际上告诉 ruby​​ 获取对象实例变量的值@memberself在类范围内,该值是类本身。

为了显示:

class Example
  @member = :member
  attr_accessor @member
end

e = Example.new
e.member = :value
e.member
 => :value
Run Code Online (Sandbox Code Playgroud)

请记住,访问未设置的实例变量会产生nil,并且由于attr方法族仅接受符号,因此您会得到:TypeError: nil is not a symbol

关于符号的使用,您可以像字符串一样使用它们。它们是出色的哈希键,因为与字符串不同,相同的符号始终引用相同的对象。

:a.object_id == :a.object_id
 => true
'a'.object_id == 'a'.object_id
 => false
Run Code Online (Sandbox Code Playgroud)

它们也通常用于引用方法名称,并且实际上可以转换为Procs,后者可以传递给方法。这就是我们能够编写诸如array.map &:to_s.

查看这篇文章以了解该符号的更多解释。