一、Symbol的定义:
Symbol是一个简单对象, 这个对象通过它的名字唯一标识。如:你每次在代码中使用:name,你是要引用一个有名字为name的对象
注意:
1、String 和Symbol两者具有紧密的联系. 每个symbol 都有个字符串的名字(可以使用to_s). 而每个String 可以请求它的相应symbol (通过 to_sym). String and Symbol 是紧密相联的, 但它们不是同一个东西.
因此, 本质上, Symbols 只是带有名字的对象
2、在程序中,不管在任何上下文中,或者在不同的上下文中,一个具体的名字或字符串总是产生同样的符号对象。
二、Symbol的使用
Jim Weirich 认为如果侧重于对象的身份,可以使用Symbol。一般运用于下面三个方面:
1、 Naming keyword options in a method argument list
2. Naming enumerated values (e.g. like enums in C).
3. Naming options in an option hash table
三 使用Symbol节省内存
如下摘自高人blog
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></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方法,意思是一样一样一样的,在李建忠的经典译本里翻译为“驻留”。
7. 可以用Symbol#all_symbols查看当前定义的全部symbol。可以体验一下自己往符号表中塞一个对象的感觉,想想你写的程序跟Ruby引擎能干一样的事情,应该还是挺爽的。
8. Python中用不着这个,因为字符串是immutable的。放下有用没用不说,有没有办法在Python中intern呢?我还没找到办法。有没有Python牛知道?
补充一下:查到了,Python中做这个事情的函数叫做 intern()。
9. 我觉得Ruby的这个设计是从Perl的glob中简化而来的。Perl中可以用*a得到对应于符号a的glob,那是一个八爪鱼一样的怪物。Ruby也可以很容易的得到symbol table中的对象,不过没有把symbol设计成八爪鱼。
10. 还有一些小问题没搞清楚,比如:name跟@name是什么关系。attr_reader :name,实际上是给attr_reader方法传了一个symbol作为参数,前者要通过这个symbol找到@name变量,是不是'@' + :name.id2name这么简单?大概可以去看看source了。
分享到:
- 2007-05-18 16:20
- 浏览 2937
- 评论(2)
- 论坛回复 / 浏览 (2 / 4069)
- 查看更多
相关推荐
解释的不错,应该明确了不少 ruby symbol详解 起因 最近在学习ruby on rails,的确是一个优秀的数据库开发框架。但在过程中,发现在视图文件夹中的rhtml文件里有大量的类似于以下的语句: <td><%= link_...
New Relic - 找到并修复Ruby错误使用New Relic的应用程序监控和故障诊断
1. 什么是Ruby?简要介绍Ruby的特点和主要用途。 2. Ruby中的变量声明和赋值规则是什么?请说明Ruby变量声明和赋值的语法。 3. Ruby中常用的数据类型有...11. 什么是Ruby中的符号(Symbol)?请说明在Ruby中符号的作用
§2.2.1 使用Ruby 10 §2.2.2 使用FreeRIDE和SciTE 11 §2.2.3 使用fxri 13 §2.3 Ruby-irb 14 §2.4 Ruby-ri 15 §2.5 RubyGems 15 第三章 类与对象 17 §3.1 类的定义 17 §3.2 对象,属性和方法 18 §3.3 继承 20...
2. 符号(Symbol)的概念及作用,如用于Hash的键。 3. Ruby中"一切皆对象"的理念,数字、布尔值、类、nil等都是对象。 4. Ruby中"一切皆表达式"的设计,控制语句、方法定义等都会返回值。 5. Ruby中"一切皆方法调用",...
The new edition of this book provides the same excellent introduction to Ruby as the previous editions plus updates for the newest version of Ruby 2.3 which includes new garbage collection support of ...
Symbol Decoration gem 提供了符号方法扩展来实现 DSL,例如where(:field.in => [1,2,3]) 。 目标是允许不同的 ORM(例如 Mongoid 和 NoBrainer)共存,因为这两个 ORM 都需要此类功能。 用法 在以下示例中: where...
符号字符串symbol-fstring是Ruby扩展,提供对符号内部字符串表示形式的访问。为什么? 在Ruby中,许多API倾向于接受符号,但是会定期在内部将其转换为字符串。 典型的示例是ActiveSupport::...
用法转发器有三种核心类型,这是Dio工作原理的中心: 动态-使用public_send进行Hash匹配,并使用Array方法强制进行Array匹配属性-使用attr_*方法作为匹配数据的来源字符串哈希-为了匹配,将String哈希像Symbol哈希...
For-Rails-Beginners::Japanese_symbol_for_beginner:Ruby on Rails的初学者有福了
该代码使用Ruby的功能组合语法-确保安装Ruby 2.6或更高版本。 用法 在Ruby解释器中运行count文件,并同时将路径和文件类型作为参数传递。 ruby count.rb /home/choltz/src/webapp/app rb 输出 将显示给定文件夹中...
Redis排行榜基础演示Ruby on Rails 展示redis如何与Ruby on Rails一起使用。屏幕截图怎么运行的?1.数据的存储方式: 公司数据存储在如下所示的哈希中: HSET "company:AAPL" symbol "AAPL" market_cap ...
Haskell库用于解析使用Marshal.dump序列化的Ruby对象的子集。 支持的类型 NilClass TrueClass | FalseClass Array Fixnum Float Hash String Symbol 如果您想增加对其他类型的支持,请随时使用以下准则创建...
IB-Ruby使用相同的概念来组织和优化运营问题,并支持研究和系统的交易工作。 列表按Enumerator进行组织,以扩展其使用范围。 该功能完全存在于文件系统中,不需要数据库,不涉及任何进一步的依赖关系。 默认情况下...
Flexibility是 ruby 类的混合体,它允许您轻松地#define方法,这些方法可以混合使用位置和关键字参数。 例如,假设我们定义 class Banner include Flexibility define ( :show , message : [ required , ...
自动检查器会使用许多不同版本的NodeJS,Ruby,Java和许多其他语言来测试您的库。 创建它的目的是为了确保您的库在语言运行库的许多版本中均可轻松运行。 与CI配合也很好! () (现在,将来可以使用NodeJS项目...
在普通使用中,它仅与TWS交换消息。 任何响应都存储在recieved-Array 。 即使那样,下订单也只需要几行代码 require 'ib-api' # connect with default parameters ib = IB :: Connection . new # define a ...
Symbol atom Exrb::NewReference或Exrb::Reference reference Exrb::Port port Exrb::Pid pid Exrb::Tuple tuple Hash map Exrb::ErlangNil [] Array `清单 Exrb::ImproperList improper_list utf...
Interrogate 尝试将类似 Scheme 的类谓词引入 Ruby。 它提供了使用Module#===的替代语法。 >> require "interrogate" >> String?("Hello") >> trues >> Symbol?(:World) >> true >> Float?(1.0) >> true 您也可以...