Ruby.inject()--需要帮助理解此代码

Ruby.inject()--需要帮助理解此代码,ruby,Ruby,此代码接受数组并仅返回唯一值 为什么此代码需要第二个“保留”才能正常工作?? 如果没有它,我会出现以下错误: NoMethodError:未定义nil:NilClass的“include”方法 类数组 def我的uniq注射 self.inject([])do | keep,num| keep第二个keep用于在第一次通过后重新初始化keep这里的do | keep,num |。参见迭代结束时文档在第二段最后一行中所说的,memo的最终值是该方法的返回值。因为inject/reduce获取块的返

此代码接受数组并仅返回唯一值

为什么此代码需要第二个“保留”才能正常工作?? 如果没有它,我会出现以下错误:

NoMethodError:未定义nil:NilClass的“include”方法

类数组
def我的uniq注射
self.inject([])do | keep,num|

keep第二个
keep
用于在第一次通过后重新初始化
keep
这里的
do | keep,num |
。参见迭代结束时文档在第二段最后一行中所说的,memo的最终值是该方法的返回值。

因为
inject
/
reduce
获取块的返回值并用它替换memo/累加器

您可以使用
每个\u和\u对象
,它不会替换备忘录

self.each_with_object([]) do |num, keep|
  keep << num unless keep.include?(num)
end
self。每个带有_对象([])的_都做| num,保留|

keep您需要
保留在块的末尾,因为块的结果将用作
inject
下一次迭代的累加器


如果没有该
keep
,块中的第一行有时会返回
keep
,但有时会返回
nil
(特别是当不满足条件时)。

第二行
keep
是必需的,因为前一行中的条件。如果
keep.include?(num)
的计算结果为false,则
nil
将返回到
inject
累加器。这并不是您真正希望发生的事情:您基本上希望跳过该迭代,但保留以前的数组。第二个
keep
允许您将数组传递回累加器。

您可能会感到困惑,因为通常
arr
inject
会在每个阶段将块的输出反馈回,并在最后返回块的输出

使用
inject
聚合数据时,需要返回在块末尾接收组合数据的对象,否则在下一次迭代中,块变量将指向其他对象,导致奇怪的效果,通常是错误


不过,您不必纯粹为了聚合而使用
inject
,理论上,如果适合您的目的,您可以切换对象。实际上,我认为很少使用
inject

作为旁注:这复制了标准库中已有的行为:
Array#uniq
self.each_with_object([]) do |num, keep|
  keep << num unless keep.include?(num)
end
arr = []
arr << 1              # [1]
arr << 2 unless false # [1, 2]
arr << 3 unless true  # nil