Ruby 是一种动态语言。没有静态编译,解释器很难提前知道谁最终会访问和修改变量。
让我们看下面的例子。你有一个string
str = "foo"
然后在你的代码中你有
str.upcase!
# => "FOO"
即使对于一个简单的解析器来说,这个例子也很容易理解字符串是变异的。但是让我们增加一些复杂性
str = "foo"
method = ["up", "case"]
str.send((method << "!").join)
# => "FOO"
这产生了与之前完全相同的结果,但该方法不是在脚本中静态编码的。相反,它是计算的结果,然后在运行时对字符串动态执行。
但是等等,让我们让它变得更复杂。
str = "foo"
method = [ARGV.first, "case"]
str.send((method << "!").join) if ARGC.to_i > 0
# => "FOO"
在这种情况下,假设我从命令行传递一个参数,转换方法将被计算然后应用于字符串。
正如您所猜想的那样,在这两种情况下,知道str
将要更改的唯一方法是实际执行代码。
这些例子也应该回答你问题的第二部分
一旦解释器开始运行,任何代码如何更改这样的字符串?如果我们说“abcd”需要被冻结,那么一定有某种方法可以改变它。
作为旁注,我想指出“冻结字符串文字”功能最近已经发展,现在将变量标记为frozen
.
在 Ruby 2.1 中,"str".freeze
编译器对它进行了优化,以在每次调用时返回一个共享的冻结字符串。最初实现了另一种“str”f 语法,但后来又恢复了。