关于调查员链的情况,我无法理解:
[1, 2, 3, 4, 5].find.map { |x| x * x }
#=> [1, 4, 9, 16, 25]
这会返回初始值方块的数组,但我希望它只返回[1]
我尝试解构所有内容,这就是我所取得的成果:.map
在原始数组的find
枚举器上调用。它会调用each
来获取迭代值。枚举器上的each
委托迭代到创建枚举数的方法,即find
。 find
获取数组的第一个元素,将其生成,然后一直生成,直到它到达示例中的块。值得到平方,块返回它,each
定义中的基础map
块返回[1],它下降到find
,因为它true
在布尔意义上,我希望find
在这一点上返回,有效地结束迭代,但不知怎的,它一直在从数组中一直提供值到map
块。
这不是一个现实世界的例子,我只是想了解如何正确阅读这些链,这个案子让我感到困惑。
UPD
由于有人多次建议find
在没有阻止的情况下调用{&#39}默认'枚举器,这是一个例子:
[1, 2, 3, 4, 5].find
#=> #<Enumerator: [1, 2, 3, 4, 5]:find>
[1, 2, 3, 4, 5].find.each { |x| x < 4 }
#=> 1
答案 0 :(得分:0)
好的,我终于明白了。
find
在块处理第一个值之后没有终止迭代的原因是,collect_i
枚举模块的collect
又名map
方法中的迭代器显式返回每次迭代后nil
,无论通过调用map
或collect
提供的块的返回值是多少。这是来自enum.c
:
static VALUE
collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
{
rb_ary_push(ary, enum_yield(argc, argv));
return Qnil;
}
因此,对初始数组的find
的内部调用总是得到nil
作为产生值的结果,因此不会停止迭代直到处理完最后一个元素。通过将ruby作为存档下载并修改此函数,可以很容易地证明这一点:
static VALUE
collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
{
rb_ary_push(ary, enum_yield(argc, argv));
return ary;
}
从修改后的源代码保存并构建ruby之后,我们得到了这个:
irb(main):001:0> [1,2,3,4,5].find.map { |x| x*x }
=> [1]
另一个有趣的事情是,Rubinius完全按照这个方式实现了collect
,所以我认为MRI和Rubinius有可能为这个陈述产生不同的结果。我现在没有安装Rubinius,但是当我有机会时我会检查这个,并用结果更新这篇文章。
不确定这对任何人是否有用,除非是为了满足一个人的好奇心,但仍然:)