多行与内联块之间的不同行为

Jac*_*ler 4 ruby activerecord ruby-on-rails

我很好奇为什么这些会产生不同的输出。所需的输出是 ActiveRecord 记录的数组。

使用内联块时,它似乎正在执行 ActiveRecord 查找,但随后将原始数组(减去rejected 元素)嵌套在另一个数组内,并将嵌套数组附加到变量。

当使用多行块时,会发生预期的行为,即发生 ActiveRecord 查找,并将识别的记录附加到变量中。

x = []
y = ["", "1353", "1155"]
x << y.reject!(&:empty?).each { |i| User.find(i) }
# => ["1353", "1155"]
x
#=> [["1353", "1155"]]
Run Code Online (Sandbox Code Playgroud)

x = []
y = ["", "1353", "1155"]
y.reject!(&:empty?)
y.each do |i|
  x << User.find(i)  
end  
# => ["1353", "1155"]
x
#=> [#<User:0x00007fc7fbacc928
#  id: 1353,
#  login: nil,
...
Run Code Online (Sandbox Code Playgroud)

sav*_*u-u 6

不同之处在于 .each 返回数组本身,所以

[1,2,3].each { nil }
# [1,2,3]
Run Code Online (Sandbox Code Playgroud)

因此,您将拒绝的 Y 数字附加到 X 中,并且您的 .each 在第一个示例中毫无用处(这也是它是数组数组的原因,因为 '<<' 将元素数组插入数组中,而不是所有个别元素)


在第二个示例中,您的“each”实际上是将元素附加到块内的数组中,因此没有“返回”依赖性。如果你想在单行上完成,你必须这样做

y.reject(&:empty?).each { |i| x << User.find(i) }
Run Code Online (Sandbox Code Playgroud)

因此它将在 de 块内进行计算,如果您希望每个循环返回块内的值,您应该使用“map”而不是“each”,并使用“concat”或“+”对数组求和(因此它对每个单独的元素求和或连接),所以

x.concat(y.reject(&:empty?).map{ |i| User.find(i) })
Run Code Online (Sandbox Code Playgroud)

OBS:正如 @tadman 在评论中建议的那样,我还删除了拒绝的“刘海”,作为“拒绝!” 方法并不期望总是返回所有值,请检查他的评论以获取更多信息

  • 这是很好的第一步,但不要忘记 [`filter_map`](https://rubyapi.org/3.2/o/enumerable#method-i-filter_map),它可以一次性完成此操作。同样需要注意的是,如果没有删除任何值,“reject!” *将返回“nil”*,这意味着它不能被链接。这应该是“拒绝”。 (4认同)