为什么Hash #select和Hash#reject将密钥传递给一元块?

我的理解是Hash#selectHash#reject每次都会传递一个键数组及其值[key, value]作为每个迭代的单个块参数,你可以使用隐式破坏性赋值直接在块中选择它们:

 {a: 1, b: 2}.select{|k, v| k == :a} # => {:a => 1} {a: 1, b: 2}.reject{|k, v| v == 1} # => {:b => 2} 

或明确的破坏性赋值:

 {a: 1, b: 2}.select{|(k, v)| k == :a} # => {:a => 1} 

我期望,当我传递一个一元块时,整个[key, value]数组将被传递,但实际上,似乎键被传递:

 {a: 1}.select{|e| pe} # => Prints `:a` (I expected `[:a, 1]`) 

为什么这样工作? 对于像map这样的其他Hash实例方法,传递整个[key, value]数组。

如果它特别设计为与二进制块相比对一元块的工作方式不同,那么我可以理解它是有用的。 但是, 我不明白为什么上面用明确的破坏性赋值的情况按原样工作。 而且没有找到任何提及此类规范的文件。

编辑我对{a: 1, b: 2}.reject{|(k, v)| v == 1}结果有误 {a: 1, b: 2}.reject{|(k, v)| v == 1} 。 这里更正:

 {a: 1, b: 2}.reject{|(k, v)| v == 1} # => {:a=>1, :b=>2} (not `{:b=>2}`) 

现在,这也表明(k, v)key ,而不是[key, value] ,所以v总是nil 。 参看 DarekNędza的评论。

它实际上总是传递两个参数。

你所观察到的仅仅是触发器和lambdas如何处理多余论点之间的区别。 块(Procs除非你告诉Ruby否则)表现得好像它有一个额外的splat并丢弃多余的参数,而lambdas(和方法对象)由于不正确的arity而拒绝调用者。

示范:

 >> p = proc { |e| pe } => # >> l = lambda { |e| pe } => # >> {a: 1}.select &p :a => {:a=>1} >> {a: 1}.select &l ArgumentError: wrong number of arguments (2 for 1) from (irb):2:in `block in irb_binding' from (irb):4:in `select' from (irb):4 from /usr/local/bin/irb:11:in `
'

顺便说一句,因为在评论中提到过:相反, map实际上传递了一个参数。 它被分配给两个不同的变量,因为你可以在赋值运算符的右侧分配多个带有数组的变量,但它实际上只是一个参数。

示范:

 >> {a: 1}.map { |k, v| pk, v } :a 1 >> {a: 1}.map &p [:a, 1] => [[:a, 1]] >> {a: 1}.map &l [:a, 1] 

并且在更改pl进一步定义:

 >> p = proc { |k, v| pk, v } => # >> l = lambda { |k, v| pk, v } => # >> {a: 1}.map &p :a 1 => [[:a, 1]] >> {a: 1}.map &l ArgumentError: wrong number of arguments (1 for 2) from (irb):2:in `block in irb_binding' from (irb):4:in `each' from (irb):4:in `map' from (irb):4 from /usr/local/bin/irb:11:in `
'