我正在学习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; “真的”是(如果它不是魔术)。
答案 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核心上提问,和/或请求一个功能来代替错误。