2013-05-08 50 views
1

我有一個小麻煩在下面的示例跟蹤自:紅寶石跟蹤自陣列#內部的每個

# a simple class 
class Foo; end 

# open the Class class to add an instance method 
class Class 
    # breakpoint 1 - self is equal to Class right here, I get why 
    puts self 

    # usage: Foo.some_method(1,2,3) 
    def some_method(*args) 
    # breakpoint 2 - when we call Foo.some_method(*args) 
    # self is equal to Foo, and once again I understand why 
    puts self 

    args.each do |arg| 
     # breakpoint 3 - self is still equal to Foo, even though we are calling each 
     # on an explicit receiver (an array called args) 
     puts self 
    end 
    end 
end 

那麼如何來自我當我打電話args數組上each不會改變?我的印象是,自我總是等於接收者,這肯定會是數組。

回答

4

self總是等於接收方在方法本身。您傳遞給每個塊的塊將在其定義的範圍內關閉,其中self等於Foo


當您考慮它時,這是非常有意義的。在C++中,應該用for循環更改this?這些塊允許您將在環境中執行的代碼傳遞給其他代碼,以便方法可以替換for或某種語言的using等語言結構,等等。

+0

啊,這使得感覺,詞彙範圍init?謝謝。 – stephenmurdoch 2013-05-08 01:00:20

+0

@stephenmurdoch:好的。 – Linuxios 2013-05-08 01:01:29

0

在Ruby中,幾乎所有東西都是可能即使它不是建議

所以,正如你所指出的,只需在正常的each塊中調用self將返回詞法範圍,即。在REPL,main

[1,2,3].each {|e| p "#{self} - #{e}" } 
# "main - 1" 
# "main - 2" 
# "main - 3" 
# => [1, 2, 3] 

但是,我們可以通過instance_eval得到我們想要的範圍,這是each接收器的實例:

[1,2,3].instance_eval { each {|e| p "#{self} - #{e}" } } 
"[1, 2, 3] - 1" 
"[1, 2, 3] - 2" 
"[1, 2, 3] - 3" 
=> [1, 2, 3] 

Periculo陀ingredere!

附錄:

我做了一個標杆只是出於好奇,從instance_eval期待一個很大的性能損失:

require 'benchmark' 

a = Array.new(1_000_000, 1) 

Benchmark.bmbm(100) do |x| 
    x.report("inline, self=main") { a.each {|e| self && e } } 
    x.report("assigned") { a.each {|e| a && e } } 
    x.report("inline, instance_eval") { a.instance_eval { each {|e| self && e } } } 
end 

這些是結果:

Rehearsal --------------------------------------------------------- 
inline, self=main  0.040000 0.000000 0.040000 ( 0.037743) 
assigned    0.040000 0.000000 0.040000 ( 0.043800) 
inline, instance_eval 0.040000 0.000000 0.040000 ( 0.041955) 
------------------------------------------------ total: 0.120000sec 

          user  system  total  real 
inline, self=main  0.030000 0.000000 0.030000 ( 0.038312) 
assigned    0.040000 0.000000 0.040000 ( 0.043693) 
inline, instance_eval 0.040000 0.000000 0.040000 ( 0.040029)