2013-05-08 2 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 

Так как прийти себя не меняется, когда я звоню each на массиве ARGS? У меня создалось впечатление, что я всегда равен получателю, который, несомненно, будет массивом?

ответ

4

self всегда равен приемнику в самом методе. Блок, который вы передаете каждому, является закрытием области, в которой он определен, где self равен Foo.


Это имеет смысл, если вы думаете об этом. В C++, должно быть изменение forthis? Блоки сделаны для того, чтобы вы могли передать свой код, который выполняет в вашу среду, в другой код, чтобы методы могли заменять языковые конструкции, такие как for или using, и так далее.

+0

Ahh, что делает смысл, лексический обзор? Благодарю. – stephenmurdoch

+0

@stephenmurdoch: Конечно. – Linuxios

0

В Ruby почти все есть возможно, даже если это не целесообразно.

Как вы отметили, просто вызывая self в нормальном блоке each, он возвращает лексическую область, т.е. в РЕПЛ, main:

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

Но, мы можем получить объем, мы хотим, который является экземпляром приемника each с помощью instance_eval:

[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) 
Смежные вопросы