【问题标题】:When to use symbols instead of strings in Ruby?何时在 Ruby 中使用符号而不是字符串?
【发布时间】:2013-05-13 07:58:00
【问题描述】:

如果我的脚本中至少有两个相同字符串的实例,我应该改用符号吗?

【问题讨论】:

    标签: ruby symbols


    【解决方案1】:

    TL;DR

    一个简单的经验法则是每次需要内部标识符时都使用符号。对于 Ruby

    完整答案

    不将它们用于动态生成的标识符的唯一原因是因为内存问题。

    这个问题很常见,因为许多编程语言没有符号,只有字符串,因此字符串也被用作代码中的标识符。您应该担心应该是什么符号,而不仅仅是何时应该使用符号。符号是标识符。如果您遵循这一理念,您很可能会做正确的事情。

    符号和字符串的实现有几个不同之处。符号最重要的一点是它们是不可变的。这意味着它们的价值永远不会改变。因此,符号的实例化速度比字符串快,并且比较两个符号等一些操作也更快。

    符号是不可变的这一事实允许 Ruby 每次引用该符号时都使用同一个对象,从而节省内存。因此,每次解释器读取:my_key 时,它都可以从内存中获取它,而不是再次实例化它。这比每次都初始化一个新字符串要便宜。

    您可以使用命令Symbol.all_symbols 获取所有已实例化的符号列表:

    symbols_count = Symbol.all_symbols.count # all_symbols is an array with all 
                                             # instantiated symbols. 
    a = :one
    puts a.object_id
    # prints 167778 
    
    a = :two
    puts a.object_id
    # prints 167858
    
    a = :one
    puts a.object_id
    # prints 167778 again - the same object_id from the first time!
    
    puts Symbol.all_symbols.count - symbols_count
    # prints 2, the two objects we created.
    

    对于 2.2 之前的 Ruby 版本,一旦一个符号被实例化,这块内存将再也不会被释放。释放内存的唯一方法是重新启动应用程序。所以符号使用不当也是造成内存泄漏的主要原因。产生内存泄漏的最简单方法是对用户输入数据使用to_sym 方法,因为该数据总是会改变,因此在软件实例中将永远使用内存的新部分。 Ruby 2.2 引入了symbol garbage collector,它释放了动态生成的符号,因此动态创建符号产生的内存泄漏不再是问题。

    回答你的问题:

    如果我的应用程序或脚本中至少有两个相同的字符串,我是否必须使用符号而不是字符串?

    如果您要查找的是要在代码内部使用的标识符,那么您应该使用符号。如果要打印输出,则应使用字符串,即使它出现多次,甚至在内存中分配两个不同的对象。

    原因如下:

    1. 打印符号将比打印字符串慢,因为它们被强制转换为字符串。
    2. 拥有大量不同的符号会增加应用程序的整体内存使用量,因为它们永远不会被释放。而且您永远不会同时使用代码中的所有字符串。

    @AlanDert 的用例

    @AlanDert:如果我在 haml 代码中多次使用 %input{type: :checkbox} 之类的东西,我应该使用什么作为复选框?

    我:是的。

    @AlanDert:但是要在 html 页面上打印出一个符号,它应该被转换为字符串,不是吗?那么使用它有什么意义呢?

    输入的类型是什么?您要使用的输入类型的标识符或要向用户显示的内容?

    的确,它会在某个时候变成 HTML 代码,但在您编写该行代码的那一刻,它意味着成为一个标识符 - 它标识您需要什么样的输入字段。因此,它会在您的代码中反复使用,并且始终具有与标识符相同的“字符串”字符,并且不会产生内存泄漏。

    也就是说,我们为什么不评估数据以查看字符串是否更快?

    这是我为此创建的一个简单基准:

    require 'benchmark'
    require 'haml'
    
    str = Benchmark.measure do
      10_000.times do
        Haml::Engine.new('%input{type: "checkbox"}').render
      end
    end.total
    
    sym = Benchmark.measure do
      10_000.times do
        Haml::Engine.new('%input{type: :checkbox}').render
      end
    end.total
    
    puts "String: " + str.to_s
    puts "Symbol: " + sym.to_s
    

    三个输出:

    # first time
    String: 5.14
    Symbol: 5.07
    #second
    String: 5.29
    Symbol: 5.050000000000001
    #third
    String: 4.7700000000000005
    Symbol: 4.68
    

    所以使用 smbols 实际上比使用字符串要快一点。这是为什么?这取决于 HAML 的实现方式。我需要对 HAML 代码进行一些修改才能看到,但是如果您继续在标识符的概念中使用符号,您的应用程序将更快更可靠。当问题出现时,对其进行基准测试并获得答案。

    【讨论】:

    【解决方案2】:

    简单地说,符号就是一个名称,由字符组成,但不可变。相反,字符串是字符的有序容器,其内容可以更改。

    【讨论】:

    • +1。符号和字符串是完全不同的东西。 除非他们被教育得很糟糕(即“一个符号只是一个不可变的字符串”的谬误)。
    • 您说得有道理,但不要回答提出的问题。 OP 将字符串与符号混淆,仅说明它是不同的东西是不够的 - 你应该帮助他理解它们的相似之处和不同之处
    • @JörgWMittag 这似乎正在整个网络上发生,除非您查看文档或有幸找到愿意解释事情真相的人。
    【解决方案3】:

    这是我在 codecademy 找到的一个不错的字符串 vs 符号基准测试:

    require 'benchmark'
    
    string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
    symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
    
    string_time = Benchmark.realtime do
      1000_000.times { string_AZ["r"] }
    end
    
    symbol_time = Benchmark.realtime do
      1000_000.times { symbol_AZ[:r] }
    end
    
    puts "String time: #{string_time} seconds."
    puts "Symbol time: #{symbol_time} seconds."
    

    输出是:

    String time: 0.21983 seconds.
    Symbol time: 0.087873 seconds.
    

    【讨论】:

    • 我们不要忘记这是十分之一秒的事实。
    • 都是相对的。有时很重要。
    • 超过一百万次迭代的百分之一秒?如果这是您可以使用的最佳优化,我认为您的程序已经得到了很好的优化。
    【解决方案4】:
    • 使用符号作为哈希键标识符

      {key: "value"}

    • 符号允许你以不同的顺序调用方法

     def write(file:, data:, mode: "ascii")
              # 为简洁起见删除
         结尾
         写(数据:123,文件:“test.txt”)
    
    • 冻结以保存为字符串并节省内存

      label = 'My Label'.freeze

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-01
      • 1970-01-01
      • 2014-09-28
      • 2014-06-19
      相关资源
      最近更新 更多