2016-06-21 9 views
-2

我最近發現許多ruby方法使用的管道輸入在某些時候並不是必需的,但這似乎不一致。例如,該行創建了昨天,今天,明天字符串數組:Ruby何時需要管道輸入? (| x | x.to_s)

DateTime.now.instance_eval{[prev_day, to_datetime, tomorrow]}.map{|d| d.strftime('%m/%d/%Y')} 
=> ["06/20/2016", "06/21/2016", "06/22/2016"] 

正如你可以instance_eval的內看到,有沒有管道輸入,函數只是假定方法正在呼籲DateTime.now。但是,如果我嘗試了同樣的想法應用到地圖的方法:

DateTime.now.instance_eval{[prev_day, to_datetime, tomorrow]}.map{strftime('%m/%d/%Y')} 
NoMethodError: undefined method `strftime' for main:Object 

突然間它試圖利用上主要的方法是什麼?

我的問題是爲什麼在第一種方法而不是第二種方法中工作?

回答

1

docs for instance_eval

Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj). In order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj's instance variables and private methods.

instance_eval,一方面是非常特殊的,因爲你把它叫做一個實例並且它明確地建立運行在實例的情況下塊。因此,該方法始終可以假定self的上下文始終是調用instance_eval的實例。

map另一方面不同的是:在您的示例調用它的一個陣列上,但塊應該在陣列內上運行的每個對象,因此就需要不同的對象傳遞給在每個塊迭代。

+0

啊哈!回顧一下我的代碼,它總是處理instance_eval。好吧,現在有道理。 – oMiKeY

+0

這實際上與'instance_eval'完全無關。一個更直接的例子是'[1,2,3] .map {chr}'和'[1,2,3] .map {| x | x.chr}'。結果是完全相同的。 –

+0

@Mike:我無法重現你的例子:'[1,2,3] .map {chr}' '的結果NameError:未定義的局部變量或方法'chr'for main:Object' on Ruby 2.3.1 – spickermann

0

When are piped inputs necessary in Ruby? (|x| x.to_s)

當塊被傳遞給具有自變量的yield的任何方法時,管道輸入是必需的。

在您的具體情況instance_eval的收益率沒有參數,而map呢。您遇到的問題與instance_eval無關。如果yield希望你傳遞一個變量,但你不這樣做,那麼它被迫假設self是主要的對象。這正是你在map的第二個例子中發生的事情。看看這個例子。

def yield_to_integer # yield integer 5 to the block 
    yield 5 
end 

yield_to_integer {|int| int.chr} # successfully run .chr() on the Integer 5 
# => "\x05" 
yield_to_integer {chr} # fails to run .chr() because it is not defined on Object 
# NameError: undefined local variable or method `chr' for main:Object