之前曾谈到了字符串扣留的概念,那么对于 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
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