【问题标题】:Using Ruby Symbols使用 Ruby 符号
【发布时间】:2012-07-11 22:47:27
【问题描述】:

我第一次尝试学习 Ruby 是在 2 年前,现在我又开始了。我停止的原因是因为我无法理解 Symbol 类。现在我又在同一点上,完全迷失在何时以及为什么使用符号。我已经阅读了 Stackoverflow 上的其他帖子,并在 Google 上搜索了一些解释。不过我还没看懂。

首先我认为符号只是一种创建某种“命名常量”的方法,而不必经历与 Java 相同的过程。

:all 

而不是用任意值public static final String ALL = 8;制作一个常量

但是,当您在例如attr_accessor :first_name etc. Symbols 只是一个轻量级的 String 类吗?我在理解应该如何解释、何时以及如何在我自己的类和框架中使用符号时遇到问题。

【问题讨论】:

  • 如果它让你感觉更好,Ruby 的创建者自己并不真正了解何时使用字符串以及何时使用符号。 Class.new.methods 在 1.8 中返回一个字符串数组,在 1.9 中返回一个符号数组。 :)

标签: ruby symbols


【解决方案1】:

在 ruby​​ 版本 2.2 删除符号 GC 后,现在凡人符号,即当我们将字符串转换为符号时 ("mortal".to_sym) 会从内存中清除。

看看这个:

require 'objspace'
ObjectSpace.count_symbols
{
  :mortal_dynamic_symbol=>3,
  :immortal_dynamic_symbol=>5,
  :immortal_static_symbol=>3663,
  :immortal_symbol=>3668
}

来源:https://www.rubyguides.com/2018/02/ruby-symbols/

【讨论】:

    【解决方案2】:

    简而言之,符号轻量级字符串,但它们也是不可变且不可垃圾回收的。

    您应该在数据处理任务中将它们用作不可变字符串(请记住,一旦创建符号,它就不能被销毁)。您通常使用符号来命名事物。

    # typical use cases
    
    # access hash value
    user = User.find(params[:id])
    
    # name something
    attr_accessor :first_name
    
    # set hash value in opts parameter
    db.collection.update(query, update, multi: true, upsert: true)  
    

    让我们举第一个例子,params[:id]。在一个中等大小的 Rails 应用程序中,可能有成百上千的那些分散在代码库中。如果我们使用字符串params["id"] 访问该值,则意味着每次都会分配新的字符串(并且之后需要收集该字符串)。在符号的情况下,它实际上是相同的 符号无处不在。减少内存分配器、垃圾收集器甚至你的工作量(: 的输入速度比 "" 快)

    如果您的代码中经常出现一个简单的单字字符串,并且您没有对其做一些时髦的事情(插值、gsub、大写等),那么它可能是一个很好的符号候选者。

    但是,这是否仅适用于用作实际程序逻辑(例如命名)的一部分的文本,而不适用于您在实际运行程序时获得的文本...例如来自用户/网络等的文本?

    我想不出我想将数据从用户/网络转换为符号的单一情况(也许除了解析命令行选项)。主要是因为后果(一旦创建的符号永远存在)。

    此外,许多编辑器为符号提供不同的颜色,以便在代码中突出显示它们。看看这个例子

    【讨论】:

    • 所以有Symbol的原因是String是可变的,所以程序员只能自己通过使用不可变类Symbol来提高程序的性能?
    • 您应该在数据处理任务中将它们用作不可变字符串(请记住,一旦创建符号,它就不能被销毁)。您通常使用符号来命名事物。
    • 所以符号是一个字符串,其属性等于static,并且在其他语言中是不可变的?
    • @Dude:是的,你可以这么说。请注意,不能用符号代替字符串。它看起来像一个字符串,但从 ruby​​ 的角度来看,它不是一个。你可以随时投,:foo.to_s
    • @yozzz:谢谢!删除了断开的链接,因为剩下的答案应该足够了。
    【解决方案3】:

    Ruby 实现通常有一个表,其中存储所有类、方法和变量的名称。它指的是通过表中的位置说一个方法名称,避免昂贵的字符串比较。但您也可以使用此表并为其添加值:symbols

    如果您编写的代码使用字符串作为标识符而不是其文本内容,请考虑使用符号。如果您编写的方法期望参数是“男性”或“女性”,请考虑使用 :male:female 。比较两个符号是否相等比字符串快(这就是符号成为良好哈希键的原因)。

    【讨论】:

      【解决方案4】:

      符号用于在语言中命名事物:类的名称、方法的名称等。 这些与字符串非常相似,只是它们永远不会被垃圾回收,并且对相等性的测试进行了优化以非常快速。

      Java 实现有一个非常相似的东西,只是它不能用于运行时使用。我的意思是,当您编写像obj.someMethod(4) 这样的java 代码时,编译器会将字符串“someMethod”转换为嵌入到.class 文件的查找表中的符号。这些符号就像不是垃圾收集的“特殊”字符串,并且可以非常快速地比较是否相等。这几乎与 Ruby 相同,只是 Ruby 允许您在运行时创建新符号,而 Java 只允许在编译时创建。

      这就像创建新方法一样——Java 在编译时允许这样做; Ruby 在运行时允许它。

      【讨论】:

        【解决方案5】:

        O'Reilly Ruby Cookbook(第 15 页)引用 Jim Weirich 的话:

        • 如果对象的内容(字符序列)很重要,请使用字符串。
        • 如果对象的身份很重要,请使用符号。

        符号通常用作哈希键,因为重要的是键的身份。使用 Object#send 等特定方法传递消息时也需要符号。

        【讨论】:

        • Object#send 不需要需要符号。
        • @SergioTulentsev 虽然当前版本的 MRI 接受此方法的字符串参数,但 earlier versions did not。即便如此,除非实现再次更改,#send 会将字符串参数转换为符号,因为这就是 Ruby 在内部识别方法名称的方式。您的里程(和具体实施)可能会有所不同。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-08
        • 2014-09-09
        • 2016-12-18
        • 2017-08-21
        • 2010-11-17
        • 2021-05-01
        相关资源
        最近更新 更多