简体   繁体   English

Ruby 块、procs 和 instance_eval

[英]Ruby block, procs and instance_eval

I recently tried to do something akin to this:我最近尝试做类似这样的事情:

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

Which gives the error:这给出了错误:

TypeError: can't convert Proc into String类型错误:无法将 Proc 转换为 String

but this works:但这有效:

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

b{ upcase }

A further look with this method:进一步看一下这个方法:

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

Yields the same Proc to String error.产生相同的Proc to String错误。

So... my understanding of blocks is that they are just procs.所以......我对块的理解是它们只是过程。 But there's obviously something special about having this & ampersand...但显然有这个&符号有一些特别之处......

Can someone explain this to me?谁可以给我解释一下这个? Is it possible to convert a normal proc to be whatever it is that is special about this &block object?是否可以将普通 proc 转换为这个&block对象的特殊之处?

edit编辑

Just figured out my second question, prepend an & to the proc... that was easy, but WHAT is this really doing?刚刚想通了我的第二个问题,在 proc 前面加上& ......这很容易,但这到底在做什么?

All you have to do for your first example to work is this:要使第一个示例工作,您所要做的就是:

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

The reason is that instance_eval needs either a string or a block and the ampersand provides the latter.原因是instance_eval需要一个字符串或一个块,而&符号提供后者。

The difference is that a.instance_eval b is passing b as a regular argument to instance_eval, whereas a.instance_eval &b is passing it as a block.不同之处在于a.instance_eval bb作为常规参数传递给 instance_eval,而a.instance_eval &b将其作为块传递。 Those are two different things.这是两个不同的东西。

Consider this method call:考虑这个方法调用:

obj.foo(bar) do |x| 
  stuff(x) 
end

That invokes the method foo with one regular argument ( bar ) and one block argument ( do |x| stuff(x) end ).它使用一个常规参数 ( bar ) 和一个块参数 ( do |x| stuff(x) end ) 调用方法foo In the method definition, they're distinguished by prefixing & to the block parameter:在方法定义中,它们通过在块参数前加上&来区分:

def foo(arg, &block)

And if you wish to pass a variable expression instead of a literal block, that is likewise accomplished by prefixing & to the expression (which should yield a Proc).如果你想传递一个变量表达式而不是一个文字块,同样可以通过在表达式前加上&来实现(它应该产生一个 Proc)。

If you pass an argument with no & , it goes in the arg slot instead of the block slot.如果你传递一个没有&的参数,它会进入arg插槽而不是插槽。 It doesn't matter that the argument happens to be an instance of Proc.参数恰好是 Proc 的一个实例并不重要。 The syntax dictates how it is passed and treated by the method.语法规定了方法如何传递和处理它。

It's because instance_eval accepts a string to eval or a block.这是因为 instance_eval 接受一个字符串来 eval 或一个块。 instance_eval(&block) is passing your block as a block to instance_eval. instance_eval(&block)正在将您的block作为块传递给 instance_eval。

The crucial difference is that a Proc instance is an object whereas a block is not an object .关键的区别在于Proc 实例是一个对象,块不是一个对象 The & is an operator that interchanges a block and a Proc instance mutually. &是一个操作符,可以相互交换块和 Proc 实例

All arguments to a method must be an object.方法的所有参数都必须是对象。 In addition to the arguments, a method can take a block.除了参数之外,方法还可以接受一个块。 instance_eval is a method that takes either a String argument or a block. instance_eval是一种接受字符串参数或块的方法。 Passing a Proc object will satisfy neither case.传递 Proc 对象不会满足这两种情况。 If you attach & to a Proc object, that will be handeled as a block.如果将&附加到 Proc 对象,它将作为块处理。

This will work:这将起作用:

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

The instance_eval method can receive an block arguments. instance_eval方法可以接收块参数。 b is a Proc . b是一个Proc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM