Ruby之symbol研究

转载 2013年09月25日 17:16:54

1. 在一个名字或者字符串前面加上冒号,得到一个symbol对象。还可以通过String#to_sym、Fixnum#to_sym和String#intern得到。

2. 一般用symbol做hash的key,号称是为了节省内存,提高执行效率。

3. 为什么可以节省内存?Ruby中的String是可变对象,这一点跟Java、C#、Python都不一样。注意跟某些C++标准库中的COW的basic_string<T>也不一样。Ruby中每一个String都可以就地改变。可能是因为这个原因,Ruby中两个内容相同的字符串文本量实际上是两个不同的对象。

    a = "hello"
    b = "hello"

    虽然俩字符串内容都一样,但是你比一下a和b,就知道a.object_id != b.object_id,它们指向的不是同一个对象。结果反而很像未经string pooling优化的C语言的行为。到底immutable好还是mutable好,或者还是貌似聪明的COW好,见仁见智了。不过Ruby的设计在把字符串用作hash key的时候毛病就大了。比如你写:

    h["ruby"].name   = "Ruby"
    h["ruby"].author = "matz"
    h["ruby"].birth_year = 1995

的时候,"ruby"这个字符串动态生成了三次,占用三倍内存。这就严重地浪费了内存。而用:ruby做为key,因为在整个运行过程中,Ruby runtime保证名为:ruby的symbol对象只有一个,所以就不用生成三个,节省内存。

4. 为什么可以提高执行效率?显然的原因是免得多次动态生成'ruby'字符串了。还不单如此,Hash的key值应该是常量,所以Ruby的Hash对于作为key的String对象都要施加保护,所谓保护,也就是把String冻结了,免得你之后还改变其值。保护当然是有代价的,symbol无需保护,当然是能提高效率的。附带说明,其他mutable的对象也可以作为hash的key,这是Ruby设计得比较奇怪的地方。在irb里运行以下代码,你会发现Ruby的Hash丢值。

    h = Hash.new
    L = [1, 2]
    h[L] = "A big object!"
    L << 3 # 居然能改! 
    h[L]   # ==> nil,找不到了,似乎正常
    # 可是
    h[[1, 2]]  # ==> nil,居然还是找不到
    # 看看keys
    h.keys     # ==> {[1, 2, 3]} 似乎还在里面
    h[[1, 2, 3]] # ==> nil
    # 可是
    h          # ==> {[1, 2, 3]=>'A big object'},明明在这里,就是找不到

    h.rehash  # ==> 这样就会一切恢复正常。
   
    这一点上Python的设计要比较容易理解,list根本就是unhashable的,不能用来做hash的key。

        回过头来在说提高效率的事。Symbol效率提高还有第三个原因,那是因为symbol本质上不比一个整数多出多少东西,用Symbol#to_i可以得到一个在整个程序中唯一的整数。Hash完全可以利用这个整数来产生hash值,那岂不是比根据字符串内容去算hash值快得多?这还是小意思,既然这个整数是唯一的,那么产生一个唯一的hash值也就是小菜一碟,要是能保证hash值唯一,那还是什么hash表,根本就变成数组了。Hash表还可能会冲突,数组根本不会冲突,百分之百保证O(1),当然快。我没看Ruby源码,不知道是不是这么处理的。

5. 为什么Ruby runtime可以保证每一个symbol唯一?因为Ruby把symbol存放在运行时维护的一个符号表里了,而这个符号表实际上是一个atom数据结构,其中存储着当前所有的程序级的name,确保不出现内容相同的多个对象。几乎每一个语言和系统都会有这样一个符号表,只不过象C/C++那样的语言,这个符号表只是在编译时存在,运行时就没了。而Python、Ruby则在运行时也保留这张表备用。有这样一个现成的数据结构干嘛不用?

6. 但是这个表中存放的并不光是我们自己主动生成的symbols,还有Ruby解释器对当前程序进行词法分析、语法分析后存在其中的、当前程序的所有名字。这可是Ruby引擎用的东西啊,我们只要加上一个冒号,就让自己的对象跟Ruby引擎内部使用的对象成邻居了。所以String#intern这个方法叫做intern(内部化)。

   .NET Framework中String类也有一个Intern方法,意思是一样一样一样的,在李建忠的经典译本里翻译为“驻留”。

理解 Ruby Symbol ,第 2 部分: Symbol 内幕

在上一篇《理解 Ruby Symbol ,第 1 部分:使用 Symbol 》中,我们大致了解了 Symbol,包括 Symbol 和 String 的区别、 Symbol 的使用等。本文我们将深入到...
  • dazhi_100
  • dazhi_100
  • 2014年04月09日 10:17
  • 399

理解 Ruby Symbol,第 1 部分

Symbol 是什么 Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。 创建一个 Sy...
  • dazhi_100
  • dazhi_100
  • 2014年04月09日 10:03
  • 408

辛星浅析ruby中的symbol

最近有位朋友问我如何理解ruby中的symbol,我也不知道如何解释,就在这里大致说一下自己的理解吧。      第一点,symbol怎么表示。         其实它和字符串的使用有点相似,它就...
  • xinguimeng
  • xinguimeng
  • 2015年11月12日 21:09
  • 317

Ruby学习笔记(20)_符号Symbol

Symbol的一篇文章结合ruby基础教程综合 博客原文What do symbols look like?This is the one area where everyone agrees. Mo...
  • slowsnowscar
  • slowsnowscar
  • 2017年11月09日 16:48
  • 120

Ruby中全局变量,实例变量,类变量,Symbol

参考自:http://rubyer.me/blog/485 http://sunnyshuhai.iteye.com/blog/286970 Ruby中全局变量,实例变量,类变...
  • huangzihao100
  • huangzihao100
  • 2013年02月05日 15:48
  • 498

ruby学习笔记(11)--symbol与hash参数

symbol是啥就不深入的讨论了,只简单说说symbol的好处 ruby内部对于每个对象,都会有一个数字id用来标识并区分,可以用xxx.object_id来查看 1 ...
  • dazhi_100
  • dazhi_100
  • 2014年04月09日 10:16
  • 349

ruby 性能研究

http://robbinfan.com/blog/40/ruby-off-rails 从Linkedin和Iron.io抛弃ruby说起 最近半年关于Ruby编程语言最负面的两条新闻莫过...
  • legend_x
  • legend_x
  • 2013年09月06日 14:16
  • 1316

Ruby String常用函数

1、 单引号中的字符串 单引号的字符串中,连续两个\会被一个\替换 例: ‘nds\\’  #->  nds\ ‘nds\\\’  #-> 出错 ‘nds\\\y’  #->  nds\\y...
  • dazhi_100
  • dazhi_100
  • 2013年07月25日 20:52
  • 8243

Cocoapods安装和使用及Ruby环境安装

作为iOS程序员,掌握 CocoaPods 的使用是必不可少的基本技能,它能帮助我们很好的管理第三方框架,减轻我们的工作,操作和安装起来也都很简单。 在安装CocoaPods之前,首先要在本地安...
  • jnbbwyth
  • jnbbwyth
  • 2016年07月15日 09:05
  • 1036

ES6详解五:Symbol

为什么要SymbolSymbol的目的就是为了实现一个唯一不重复不可变的值,任何一个Symbol都是唯一的,不会和其他任何Symbol相等。很多时候其实我们都需要用到唯一不重复的值。比如我们给一个DO...
  • lihongxun945
  • lihongxun945
  • 2015年09月18日 21:43
  • 2413
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Ruby之symbol研究
举报原因:
原因补充:

(最多只允许输入30个字)