Ruby跟踪自己在Array#each中

时间:2013-05-08 00:22:22

标签: ruby self

我在以下示例中跟踪自我时遇到了一些麻烦:

# 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时, self 怎么没有改变?我的印象是自我总是等于接收器,这肯定是阵列?

2 个答案:

答案 0 :(得分:4)

self始终等于方法本身中的接收器。传递给每个块的块是定义它的作用域的闭包,其中self等于Foo


当你想到它时,这是完全合理的。在C ++中,for循环应该更改this吗?使用块来允许您将在您的环境中执行的代码传递给其他代码,以便方法可以替换for或某些语言using等语言结构,等等上。

答案 1 :(得分:0)

在Ruby中,即使它不是可取的,几乎任何东西都可能

正如您所指出的,只需在普通self块中调用each即可返回词法范围,即。在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 tuo 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)