Ruby lambda的proc和'instance_eval'

时间:2018-10-03 02:34:11

标签: ruby

当我将lambda传递给instance_eval作为块时,它似乎传递了一个额外的参数:

lamb = -> { puts 'hi' }
proc = Proc.new { puts 'hi' }
instance_eval(&lamb)
# >> ArgumentError: wrong number of arguments (given 1, expected 0)
#    from (irb):5:in `block in irb_binding'
#    from (irb):7:in `instance_eval'
instance_eval(&proc)
# => hi
instance_exec(&lamb)
# => hi

为什么会这样?请注意,此问题与lambda为什么会引发错误无关。这是众所周知的。问题在于为什么instance_eval发送接收者的self作为参数。不需要它,并且令人困惑。而且AFAIK没有记录。

This有帮助,但没有解释为什么红宝石会这样做。 instance_eval的重点是将self设置为接收者;为什么还要通过将self传递给proc来混淆事物呢?

1 个答案:

答案 0 :(得分:3)

来自文档

  

对于使用lambda或->()创建的proc,如果   错误数量的参数通过多个传递给Proc   参数。对于使用Proc.new或Kernel.proc创建的proc,额外   参数会被静默丢弃。

在您的情况下,lambproc都用一个参数调用了

From the docs of instance_eval

  

给instance_eval一个块时,obj也作为   阻止的唯一论点

instance_evalBasicObject类的方法,可以在实例中调用。因此,例如,给定的块将可以访问私有方法。

class Test
  def call
    secret_number + 100
  end
  private
  def secret_number
    42
  end
end

test = Test.new
show_secret = -> (obj) { puts secret_number }

test.instance_eval(&show_secret) # print 42

没有当前上下文的实例self将作为参数传递。我认为instance_eval的设计目的是为了在对象内调用它。

From the docs of instance_eval

  

为了设置上下文,将变量self设置为obj,而将   代码正在执行,使代码可以访问obj的实例变量   和私有方法。