我们可以从很多着名的存储库中轻松找到这种风格,如机架,导轨等。
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
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
它没有任何区别,为什么人们会冻结常量?
答案 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)