2016-01-06 50 views
3

當我使用mapselect和其他Enumerable方法時,我注意到以下差異。當使用do ... end blocks時,與map,select等不同的行爲

假設我們有一個哈希象下面這樣:

h = {a: 1} 

下面的代碼打印的select輸出符合市場預期。

p h.select { |k, v| true } 
#=> {:a=>1} 

然而,下面的代碼顯示輸出是Enumerator,即使當已提供的塊。

p h.select do |k, v| 
    true 
end 
#=> #<Enumerator: {:a=>1}:select> 

任何想法的行爲爲什麼這種差異?我經常遇到這個問題,因爲我在工作時一直使用檢查p,這種行爲經常使我的思維過程出軌。

回答

4

運算符優先事項。

p h.select do |k, v| true end 

實際上執行爲:

(p h.select) do |k, v| true end 

p h.select { |k, v| true } 

作爲被處理:

p (h.select { |k, v| true }) 

Enumerable#select,稱爲無塊,返回一個枚舉器。

+0

什麼是出路,我需要在其周圍放置括號來解決優先。 –

+0

這完全取決於你。而且,是的,括號會起作用。 – mudasobwa

+0

它可能不是運算符優先級,可能是如何解釋函數調用的參數。是否更有可能發生評估爲'p(h.inspect)do..end'而不是'(p h.select)do ... end'? –

0

根據官方文檔網站

返回由,該塊返回true條目的新的哈希。

如果未指定塊,則返回枚舉數。

下面是該方法的代碼用C

rb_hash_select(VALUE hash) 
{ 
    VALUE result; 

    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size); 
    result = rb_hash_new(); 
    if (!RHASH_EMPTY_P(hash)) { 
     rb_hash_foreach(hash, select_i, result); 
    } 
    return result; 
} 

http://ruby-doc.org/core-2.3.0/Hash.html#method-i-select

+1

我提供了一個塊,它仍然返回一個枚舉器 –

+0

那麼它可能不是選擇方法?但寧可與p方法? –

+0

似乎是從其他答案 –

2

我認爲@ mudasobwa的答案基本上是正確的,但我想澄清實際發生的優先順序。

當你這樣做:

p h.select do |k, v| 
    true 
end 

...你實際上這樣做:

p(h.select) do |k, v| 
    true 
end 

換句話說,你傳遞的h.select的結果(無參數,它返回一個枚舉器)作爲p的參數,並且您還將一個塊參數傳遞給pp顯然默默地忽略了塊參數。

相反,當你這樣做:

p h.select {|k, v| true } 

...你實際上這樣做:

p(h.select {|k, v| true }) 

也就是說,你傳遞的h.select { |k, v| true }的結果p,這給你你期望的結果。

如果你想使用do...end語法和得到你想要的結果,你必須包裝在括號中的整個事情:

p(h.select do |k, v| 
    true 
end) 

這不是很漂亮,但它的工作原理。

+0

任何想法爲什麼'do ... end'和'{...}'不會被視爲'p'的塊,如您的答案的第一種情況所示 –

+0

不要擔心,我從中得到了答案另一個[SO線程](http://stackoverflow.com/questions/5587264/do-end-vs-curly-braces-for-blocks-in-ruby)。 –

+1

我不能解釋它,只能說解析器是如何工作的。可能有一些技術原因,但我懷疑這只是一個設計選擇。每種風格都有一個很好的用例,但不幸的是,它有時會讓人無視警惕。 –

相關問題