Ruby块,procs和instance_eval

时间:2011-06-16 13:24:13

标签: ruby block lambda proc-object

我最近尝试做类似的事情:

a = "some string"
b = Proc.new{ upcase }
a.instance_eval b

出现错误:

  

TypeError:无法将Proc转换为String

但这有效:

def b(&block)
  "some string".instance_eval &block
end

b{ upcase }

使用此方法进一步了解:

def b(&block)
  "some string".instance_eval block
end

产生相同的Proc to String错误。

所以...我对积木的理解是它们只是触发器。但显然有一些关于这个&&符号的特别之处......

有人可以向我解释一下吗?是否有可能将正常的proc转换为对这个&block对象特殊的东西?

修改

刚刚想出了我的第二个问题,在问题上添加了& ...这很容易,但这是真的在做什么?

5 个答案:

答案 0 :(得分:22)

你需要做的第一个工作就是:

>> a.instance_eval &b #=> "SOME STRING"

原因是instance_eval需要一个字符串或一个块,而&符号需要后者。

为了理解块和触发器之间的差异,可能以下博客文章有助于:

Understanding Ruby Blocks, Procs and Lambdas

答案 1 :(得分:9)

不同之处在于 a.instance_eval b b 作为instance_eval的常规参数传递,而 a.instance_eval& b 是把它作为一个块传递。这是两件不同的事情。

考虑这个方法调用:

obj.foo(bar)do | x |东西(x)结束

使用一个常规参数( bar )和一个块参数( do | x | stuff(x)end )调用方法 foo )。在方法定义中,它们通过在& 前加上块参数来区分:

def foo(arg,& block)
  ...
  的

如果你希望传递一个变量表达式而不是一个文字块,那么同样通过在表达式前面添加& 来实现这一点(它应该产生一个Proc)。

如果您传递的参数没有& ,则会进入 arg 插槽而不是插槽。论证恰好是Proc的一个实例并不重要。语法规定了该方法如何传递和处理它。

答案 2 :(得分:1)

这是因为instance_eval接受一个字符串到eval或一个块。 instance_eval(&block)正在将block作为块传递给instance_eval。

答案 3 :(得分:1)

关键的区别在于一个Proc实例是一个对象一个块不是一个对象&相互交换块和Proc实例的运算符。

方法的所有参数都必须是对象。除了参数之外,方法可以采用块。 instance_eval是一个接受String参数或块的方法。传递Proc对象将既不满足也不满足。如果将&附加到Proc对象,则将其作为块进行处理。

答案 4 :(得分:0)

这将有效:

a = "some string"
b = Proc.new{ upcase }
a.instance_eval &b

instance_eval方法可以接收块参数。 bProc