def hello(z) "hello".gsub(/(o)/,&z) end z = proc {|m| p $1} hello(z) # prints: nil
def hello z = proc {|m| p $1} "hello".gsub(/(o)/,&z) end hello # prints: "o"
为什么这两段代码的输出不同?有没有办法从方法定义外部将块传递给gsub,以便以与在方法定义中给出块的方式相同的方式计算变量$1,$2?
解决方法
Why the output is different?
ruby中的proc具有词法范围.这意味着当它找到一个未定义的变量时,它会在上下文中解析proc被定义,而不是被调用.这解释了代码的行为.
您可以看到在regexp之前定义了块,这可能会导致混淆.这个问题涉及一个魔法ruby变量,它与其他变量的工作方式完全不同. Citing @JörgWMittag
It’s rather simple,really: the reason why $SAFE doesn’t behave like you would expect from a global variable is because it isn’t a global variable. It’s a magic unicorn thingamajiggy.
There are quite a few of those magic unicorn thingamajiggies in Ruby,and they are unfortunately not very well documented (not at all documented,in fact),as the developers of the alternative Ruby implementations found out the hard way. These thingamajiggies all behave differently and (seemingly) inconsistently,and pretty much the only two things they have in common is that they look like global variables but don’t behave like them.
Some have local scope. Some have thread-local scope. Some magically change without anyone ever assigning to them. Some have magic meaning for the interpreter and change how the language behaves. Some have other weird semantics attached to them.
如果你真的想要找到$1和$2变量的确切工作方式,我认为你会发现的唯一“文档”是rubyspec,这是rubin人员艰难地完成的ruby规范.有一个很好的黑客,但要为痛苦做好准备.
Is there a way to pass a block to gsub from another context with $1,$2 variables setup the right way?
你可以通过以下修改实现你想要的东西(但我打赌你已经知道了)
require 'pp' def hello(z) #z = proc {|m| pp $1} "hello".gsub(/(o)/,&z) end z = proc {|m| pp m} hello(z)
我不知道有办法在飞行中改变过程的范围.但你真的想这样做吗?