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 数组时,为什么self不会改变?each我的印象是 self 总是等于接收者,那肯定是数组?

4

2 回答 2

4

self总是等于方法本身的接收者。传递给 each 的块是定义它的范围的闭包,其中self等于 a Foo


当你考虑它时,这是完全有道理的。在 C++ 中,应该for改变循环this吗?制作块以允许您将在您的环境中执行的代码传递给其他代码,以便方法可以替换语言结构,如for,或某些语言的using,等等。

于 2013-05-08T00:50:38.703 回答
0

在 Ruby 中,几乎任何事情都是可能的,即使是不可取的。

因此,正如您所指出的,简单地调用self普通each块将返回词法范围,即。在 REPL 中,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 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)
于 2017-02-13T23:03:06.983 回答