正则表达式字面值的对象构建


之前曾谈到了字符串扣留的概念,那么对于 Ruby 的正则表达式 Regexp 类型来说,是否也有类似的常量池机制呢?

(注:以下输出的具体数字随环境而变,重要的是其前后的相等性)

我们可以做一个简单的测试:

2.times { p "foo".object_id }
2.times { p :foo.object_id }
2.times { p /foo/.object_id }

输出:

5712492
5712432
146408
146408
5713608
5713608

根据输出结果,我们似乎可以得出结论, Regexp 类型也有类似字符串扣留的机制。然而细心的人会进一步测试这段代码:

2.times { p Regexp.new(/foo/).object_id }

输出了两个不同的数字。这和之前的测试难道不是矛盾的吗?当然不是,这实际上和 Ruby 的语法分析器有关。

Ruby 支持正则表达式字面值(/…/)。对于官方的 Ruby 实现来说,其语法分析器会在接受一个正则表达式的单词(token)时生成该正则表达式对象。也就是说,字面值形式的正则表达式是在语法分析时生成的,也可以宏观地看作是在编译时生成的。因此,在运行时,虽然会多次调用 /foo/.object_id,但由于语法分析器只看到了一个正则表达式字面值,其接收者永远都是一个对象。

证明:

ObjectSpace.each_object(Regexp) { |r| p r }
/foo/

第一行是打印出当前的 Ruby 实例中所有 Regexp 对象,而这时解释器还没执行到第二行的字面值。实际的输出中,也确实包含 /foo/ 这个对象。

如果语法分析器看到两个正则表达式字面值,自然也就会生成两个 Regexp 对象了:

p /foo/.object_id, /foo/.object_id

输出:

5713896
5713812

One Comment

  1. Posted 2019/06/25 at 16:41 | Permalink | Reply

    Great blog right here! Also your site a lot uup fast!
    What web host are you the usage of? Can I am getting your associate hyperlink for
    your host? I wish my web site loaded up as quickly as yours lol

Leave a comment