【问题标题】:Ruby 2.1 Frozen stringRuby 2.1 冻结字符串
【发布时间】:2013-10-04 02:00:17
【问题描述】:

Ruby 2.1 将有一个冻结字符串,因此每次解释器运行时都不会重新创建对象,即

my_hash["abcd"f] = 123

为什么解释器不能自动检测到这个字符串不会改变而只是自动冻结它?

或者,pre-ruby 2.1 一旦解释器开始运行,任何代码如何更改这样的字符串?如果我们说“abcd”需要被冻结,那么一定有一些方法可以改变它。

-- 更新:上面的问题已经更新,所以下面的 cmets 有点尴尬,但解决了之前的代码示例,它不是那么好。

-- 更新:http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/ Ruby 密钥会自动冻结。

【问题讨论】:

  • 考虑mydef.downcase!,它将修改返回的字符串。现在,如果你想在 pre-2.1 中冻结/保留字符串,你只需要使用符号。

标签: ruby string ruby-2.1


【解决方案1】:

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 语法,但后来又恢复了。

【讨论】:

    【解决方案2】:
    • 关于你的第一个问题:

      因为解释器无法预见该字符串实例以后是否会被任何破坏性方法修改。

    • 关于你的第二个问题(在“或”之后):

      通过String上的任意破坏方法,如reverse!prependconcat

    【讨论】:

    • 如果字符串被自动冻结,mydef.sub!('a','o') 会抛出一个不需要的 RuntimeError。这是你观点的一个例子吗? (这取代了之前措辞不佳的评论j。)
    • 我试过 mydef.sub!('a','!')。 mydef 仍将在下一次调用时返回 'abcd'。
    • 我清理了@CarySwoveland 的措辞
    • 我清理了@sawa 的措辞
    • @Daniel - 我的意思是,如果 Ruby 将 def mydef() "abcd" end 视为 def mydef() "abcd".freeze endmydef.sub!("a","o") => RuntimeError: can't modify frozen String (v 2.0.0)(尽管 @987654329 @ 将继续返回“abcd”)。所以我们不希望 Ruby 冻结字符串。我认为这是sawa的观点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    相关资源
    最近更新 更多