为什么到处都有冷冻常数?

时间:2014-12-30 09:14:40

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4 rack

我们可以从很多着名的存储库中轻松找到这种风格,如机架,导轨等。

For example in rack

PATH_INFO      = 'PATH_INFO'.freeze
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
SCRIPT_NAME    = 'SCRIPT_NAME'.freeze
QUERY_STRING   = 'QUERY_STRING'.freeze
CACHE_CONTROL  = 'Cache-Control'.freeze
CONTENT_LENGTH = 'Content-Length'.freeze
CONTENT_TYPE   = 'Content-Type'.freeze

Another examle in rails

HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
HTTP_IF_NONE_MATCH     = 'HTTP_IF_NONE_MATCH'.freeze
HTTP_IF_NONE_MATCH     = 'HTTP_IF_NONE_MATCH'.freeze

我想知道为什么这些常量字符串被冻结了。因为它们都是常量,所以应该只有一个实例。当然,我们可以将"foo".freeze放在某处以引用相同的单例实例,但是人们通常会像HTTP_IF_MODIFIED_SINCE那样编写文字变量名。

所以在我看来,尽管使用#freeze它没有任何区别,为什么人们会冻结常量?

3 个答案:

答案 0 :(得分:27)

当您为已经初始化的常量重新赋值时,Ruby会打印警告是正确的:

> FOO = 'foo'
> FOO = 'bar'
# :2: warning: already initialized constant FOO
# :1: warning: previous definition of FOO was here
> FOO
# => "bar"

但是没有保护不改变常数中的值。没有freeze的示例:

> FOO = 'foo'
> FOO[1] = '-'
> FOO
# => "f-o"

但是freeze允许保护常量的值不被改变。 freeze的示例:

> FOO = 'foo'.freeze
> FOO[1] = '-'
# => RuntimeError: can't modify frozen String

答案 1 :(得分:6)

通常Rubyist冻结字符串文字以使执行更快。如果在某些控制器中存在某些函数调用,例如下面的函数,则每个请求都将调用该函数。

log("debug".freeze)

ruby​​每次都会定义一个新的垃圾字符串对象。对象分配不是免费的。它消耗内存和CPU。垃圾将在那里,直到GC收集它们。

但如果文字被冻结

# frozen_string_literal: true

ruby​​分配一次并将其缓存以供以后使用。此外,字符串对象将是不可变的,并且可以安全地在多线程环境中使用。

  

从红宝石3.0中,红宝石会冻结每根绳子, - 根据马茨的说法。

<强>更新

如果在ruby文件的开头添加以下注释,则整个文件中的每个字符串文字都将是不可变的。当您尝试针对多线程环境优化应用时,这非常有用。

--enable-frozen-string-literal

或者您甚至可以使用<!DOCTYPE HTML> <html> <head> <script src="http://www.webglearth.com/v2/api.js"></script> <script src="https://d3js.org/d3.v4.min.js"></script> <script> function initialize() { var earth = new WE.map('earth_div'); WE.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(earth); //get the csv file data, create new marker [latitude,longitude] //the bind popup will get the field country for (var i = 0; i < 5; i++) { var marker = WE.marker([i,i]).addTo(earth); marker.bindPopup("<b>The data </b><br><a target=_blank href='http://www.google.com'>link</a>.<br />" , { maxWidth: 150, closeButton: true }).closePopup(); }//end for i var markerCustom = WE.marker([50, -9], '/img/logo-webglearth-white-100.png', 100, 24).addTo(earth); earth.setView([0, 0], 3); } </script> <style> html, body { padding: 0; margin: 0; background-color: black; } #earth_div { top: 0; right: 0; bottom: 0; left: 0; position: absolute !important; } </style> <title>WebGL Earth API: Markers</title> </head> <body onload="initialize()"> <div id="earth_div"></div> </body> </html>开关启动Ruby流程。

答案 2 :(得分:1)

为什么你看到流行项目中常量冻结常量的一个原因是他们使用代码分析器Rubocop

这是一个标准的Rubocop rule,由于@spickermann上面提到的原因,常数不应该是可变的。