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

我的理解是, Hash#selectHash#reject每次都会传递一个key数组及其值[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| p e} # => 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的评论。


它总是传递两个参数。

你所观察到的仅仅是特效和lambda对待多余论点的区别。 块(除非你以其他方式告诉Ruby),它的行为就好像它有一个额外的splat并放弃了多余的参数,而lambda(和方法对象)由于不正确的arity而拒绝调用者。

示范:

>> p = proc { |e| p e }
=> #<Proc:0x007f8dfa1c8b50@(irb):1>
>> l = lambda { |e| p e }
=> #<Proc:0x007f8dfa838620@(irb):2 (lambda)>
>> {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 `<main>'

另外,由于它在评论: map提到,相反,实际上传递了一个参数。 它被分配给两个不同的变量,因为您可以在赋值运算符的右侧使用一个数组分配多个变量,但它始终是一个参数。

示范:

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

当改变pl进一步定义时:

>> p = proc { |k, v| p k, v }
=> #<Proc:0x007ffd94089258@(irb):1>
>> l = lambda { |k, v| p k, v }
=> #<Proc:0x007ffd940783e0@(irb):2 (lambda)>
>> {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 `<main>'
链接地址: http://www.djcxy.com/p/60957.html

上一篇: Why does Hash#select and Hash#reject pass a key to a unary block?

下一篇: Subclassing Ruby Hash, object has no methods of Hash?