在 Ruby 中,从技术上讲,没有块的 array.reject 或 array.select 有什么作用?

In Ruby, what - technically - does array.reject or array.select without a block do?

据我所知,array.rejectarray.select 什么都不做:

[nil, false, true].reject  # Should have been reject.to_a for this example.
 => [nil, false, true] 
[nil, false, true].select  # Should have been select.to_a for this example.
 => [nil, false, true] 

对于我尝试编写的代码,compact 是我所需要的,但我很好奇为什么没有块的 rejectselect 什么都不做 - 我是期望默认块 { |e| e } 所以 reject 将是 compact 而 'select' 将是一些奇怪的反紧凑。

默认块在做什么?


编辑:抱歉,我漏掉了上面表达式末尾的“.to_a”,我希望这会触发某种惰性求值并使 reject/select 枚举执行有用的东西。我通常剪切和粘贴我的例子以避免这种事情。

对其进行 Enumerator

en = [1,2,3].reject
# => #<Enumerator: [1, 2, 3]:reject>
en.each{|n| n == 1}
# => [2, 3]

块对于许多 Ruby 方法是可选的。当没有给出块时,枚举器通常是 returned。您可能需要枚举器至少有几个原因。

#1 将枚举器与 class Enumerator.

中的方法一起使用

这是一个例子。假设您希望改变字符串中字母的大小写。一种常规方式是:

"oh happy day".each_char.with_index.map { |c,i| i.odd? ? c.upcase : c.downcase }.join
  #=> "oH HaPpY DaY" 

但你可以这样写:

enum = [:odd, :even].cycle
"oh happy day".each_char.map { |c| enum.next==:odd ? c.upcase : c.downcase }.join

或者

enum = [:upcase, :downcase].cycle
"oh happy day".each_char.map { |c| c.send(enum.next) }.join

请参阅 Array#cycle and Enumerator#next 的文档。

#2 使用枚举器链接方法

在我上面的第一个例子中,我写道:

"oh happy day".each_char.with_index.map...

如果您查看 String#each_char and Enumerator#with_index 的文档,您会发现这两种方法都可以使用或不使用块。在这里,它们都在没有块的情况下使用。这使得这三个方法可以 链接 .

研究以下 return 值。

enum0 = "oh happy day".each_char
  #=> #<Enumerator: "oh happy day":each_char> 
enum1 = enum0.with_index
  #=> #<Enumerator: #<Enumerator: "oh happy day":each_char>:with_index> 
enum2 = enum1.map
  #=> #<Enumerator: #<Enumerator: #<Enumerator:
  #     "oh happy day":each_char>:with_index>:map> 

您可能希望将 enum1enum2 视为 "compound" 枚举数。

您显示的 return 值:

[nil, false, true].reject

成为:

#=> [nil, false, true]

但这是不正确的。 return 值为:

#<Enumerator: [nil, false, true]:reject>

如果我们写:

enum = [nil, false, true].reject

然后:

enum.each { |e| e }
  #=> [nil, false] 

(从 Ruby v2.3 开始,我们可以写成 enum.reject(&:itself))。这使用方法 Enumerator#each, causing enum to invoke Array#each 因为 reject 的接收者是 class Array 的一个实例。