为什么Ruby全局字符串,如$&amp ;,忽略突变而没有错误?

时间:2013-02-28 17:34:57

标签: ruby pseudo-globals

我正在学习Ruby(2.0),这让我很吃惊:

s = "1234"
s =~ /\d+/
$&  ==> "1234"       # as expected, $& contains the matched string
$&.slice!(-2..-1)    # should mutate string
$&  ==> "1234"       # what?
s.slice(-2..-1) 
s  ==> "12"          # as expected

slice!方法应该改变字符串。其他mutator方法的行为方式相同。我的问题:为什么这不会引发错误,这是我所期望的,当一个函数无法完成它所说的那样的事情时?这是在某处记录的吗?有理由吗?

更新

所以,我发现$&并不像全局变量那样。每次引用它都会给出一个新对象,好像它实际上是一个无参数函数:

irb> $foo = "1234"
=> "1234"
irb> $foo.object_id
=> 70205012205980
irb> $foo.object_id
=> 70205012205980   # the same
irb> $&.object_id
=> 70205003531300
irb> $&.object_id   
=> 70205011619040   # different object

所以...我的问题变成了:这是解释器中的“魔术”,还是$&实际上是一个无法使用函数,正如我在Ruby中使用def ... end定义的那样?而且,我怎么能分辨出来呢?在Python中,我可以通过使用它的名称来引用函数foo

>>> foo
<function foo at 0x10d3117d0>

有没有办法在Ruby中做到这一点?然后我可以看看$&amp; “真的”是(如果它不是魔术)。

3 个答案:

答案 0 :(得分:5)

Ruby C API包含 hooked 虚拟变量。来自README.EXT

  

您可以定义钩子变量。访问器功能(getter和   在访问钩子变量时调用setter。

void rb_define_hooked_variable(const char *name, VALUE *var,
           VALUE (*getter)(), void (*setter)())
     

如果你需要提供setter或getter,只需提供0即可   钩你不需要。如果两个钩子都是0,则rb_define_hooked_variable()   就像rb_define_variable()。

一样      

getter和setter函数的原型如下:

VALUE (*getter)(ID id, VALUE *var);
void (*setter)(VALUE val, ID id, VALUE *var);
     

此外,您可以定义没有相应C的Ruby全局变量   变量。变量的值只能通过钩子设置/获取。

 void rb_define_virtual_variable(const char *name,
            VALUE (*getter)(), void (*setter)())
     

getter和setter函数的原型如下:

VALUE (*getter)(ID id);
void (*setter)(VALUE val, ID id);

$&是虚拟变量的示例,它在re.c中定义,相应的getter是last_match_getter,并且没有关联的setter。

所以$&在某种意义上是一个无参数函数,只有它是用C实现的。你不能(据我所知)在纯中定义你自己的虚拟全局变量Ruby(如果你创建自己的C扩展,你可以。)

答案 1 :(得分:2)

由于$&的目的是告诉你匹配的内容,因此匹配应该是唯一可以更新匹配的操作。

答案 2 :(得分:1)

这是一个有趣的问题。杰作纳的回答和对这个问题的许多评论只是说这样做是没有用的,但这并没有回答这个问题。无论是否应该在实际代码中完成,OP的问题仍然存在。

问题的答案是,这看起来像只读字符串的功能。将破坏性操作应用于只读字符串时,它将返回不同的字符串对象。我同意OP的说法很奇怪。它应该引发错误。

除非有人提出令人信服的解释,否则我建议您在Ruby核心上提问,和/或请求一个功能来代替错误。