对整数调用Ruby.times方法。它如何知道将每个整数作为块中的参数进行迭代?

对整数调用Ruby.times方法。它如何知道将每个整数作为块中的参数进行迭代?,ruby,Ruby,我在阅读时遇到了以下示例: def meth_three 100.times do |num| square = num*num return num, square if square > 1000 end end 如果在irb中调用meth_three,它将返回第一个介于1和100之间的整数,该整数的平方为1000: meth_three # => [32, 1024] 我的问题是,times方法如何知道如何循环1到100之间的每个整数,以作为参数传递

我在阅读时遇到了以下示例:

def meth_three
  100.times do |num|
    square = num*num
    return num, square if square > 1000
  end
end
如果在irb中调用
meth_three
,它将返回第一个介于1和100之间的整数,该整数的平方为
1000

meth_three # => [32, 1024]

我的问题是,
times
方法如何知道如何循环1到100之间的每个整数,以作为参数传递给
|num |
参数?

times
方法实际返回一个值,该值是当前迭代器的每个循环(1,2,3…100)。

do
关键字捕获此迭代器,并将其用作变量
num



无论何时看到
num
变量,都会看到当前迭代器,该迭代器由
times

返回,其中一些注释会提示正在发生的事情。我认为可以这样解释:

class Integer
  def times(&block)
    if self.value > 0
      for i in 0...self.value do
        block.call(i)
      end
    end
  end
end
Ruby中的每个整数实际上都是一个对象,更具体地说是
integer
类的一个实例

您可以将其视为一个
Integer#times
方法,可以天真地实现如下内容:

class Integer
  def times(&block)
    if self.value > 0
      for i in 0...self.value do
        block.call(i)
      end
    end
  end
end

这个方法实际上是在ruby(MRI)的官方版本中用C实现的,正如在您的问题的一条评论中所指出的。我在这里只写了一些类似的东西来帮助解释它在Ruby中的外观概念。

在Ruby中编写迭代有很多不同的方法

以下是一种可能的递归实现方法:

类整数
def时间(&blk)
返回(uuu被调用方uuu)的枚举u,除非给出块u?
返回自我,除非是积极的?
预定时间(&blk)
产量预测
结束
结束
或者,使用
范围#每个

类整数
def时间(&blk)
返回(uuu被调用方uuu)的枚举u,除非给出块u?
返回自我,除非是积极的?
(0…自我)。每个(&blk)
自己
结束
结束
或者,使用循环:

类整数
def时间
返回(uuu被调用方uuu)的枚举u,除非给出块u?
返回自我,除非是积极的?
i=-1
当(i+=1)
还有一个尾部递归实现,只是为了好玩:

类整数
def时间(&blk)
返回(uuu被调用方uuu)的枚举u,除非给出块u?
返回自我,除非是积极的?
__时间记录(0,&blk)
自己
结束
专用定义时间记录(i和blk)
除非我自己回来
产量一
__时间记录(i.succ和blk)
结束
结束
以下是来自实际Ruby实现的实际代码(来自):

def时间
返回到_enum(:times){self},除非给出块_?
i=0
而我自己
产量一
i+=1
结束
自己
结束
使用与(请参阅)完全相同的代码(请参阅)

下面是另一个来自真实Ruby实现的真实示例(来自):

def时间(&block)
返回(:times){self}的enum_,除非是块
%x{
对于(变量i=0;i

正如您所看到的,有很多方法可以用Ruby编写循环。

它不“知道”,它只是用这种方式编程的。你能不能更具体一点,具体是什么,你不清楚?“这个方法实际上是用C实现的,以提高性能”——这根本不是事实。在Rubinius、TruffleRuby和JRuby中,它是用Ruby实现的。在JRuby和TruffleRuby中,它过去是用Java实现的,但他们用Rubinius的Ruby版本取代了它,这正是因为它在Ruby中的性能更高。在Opal中,它是通过内嵌ECMAScript在Ruby中实现的。在IronRuby中,它是用C#实现的。我很久没有研究过MagLev了,但我很确定它是在Ruby或Smalltalk中实现的。在MacRuby中,它是Objective-C。非常感谢您提供这条信息!我不知道。尽管如此,它仍然在MRI中以C语言实现。我想我只是认为性能是原因。Rbinius、TruffleRuby和JRuby有大量优化编译器。当然,Ruby编译器只能优化Ruby代码,而不能优化Java或C。这就是为什么用Ruby重写东西可以更快。特别是因为优化器可以将块内的调用内联到
times
方法中,然后将
times
方法内联到调用者中,这也只有在所有方法都使用相同的语言时才有效。是的,当然!这是有道理的。由于性能方面的原因,我删除了关于
时代
在C中实现的艺术,并且更清楚地表明MRI版本仍然在C中实现,我认为大多数学习Ruby的人可能会使用MRI。再次感谢您指出这一点:)“我认为大多数学习Ruby的人可能会使用MRI。”–不幸的是:-D事实上,您可以深入研究Rubinius,并且几乎所有您遇到的东西仍然是Ruby,这将是一次非常棒的学习体验。想知道一种方法是如何工作的吗?只要读一读,你甚至不必学习一门新语言。谢谢@Viktor,我已经更改了我的答案以反映你的反馈:)