一、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
- 浏览 2979
- 评论(2)
- 论坛回复 / 浏览 (2 / 4095)
- 查看更多
相关推荐
解释的不错,应该明确了不少 ruby symbol详解 起因 最近在学习ruby on rails,的确是一个优秀的数据库开发框架。但在过程中,发现在视图文件夹中的rhtml文件里有大量的类似于以下的语句: <td><%= link_...
在 Ruby 中,符号通常使用前缀 `:` 来表示,例如 `:symbol`。 #### 符号的创建和使用 符号可以直接通过名称创建,也可以通过字符串转换而来。 ##### 创建符号 ```ruby my_symbol = :my_symbol puts my_symbol....
在Ruby环境中,New Relic能够深入到代码层面,跟踪数据库查询、HTTP请求、线程和内存使用情况,从而提供详尽的应用性能视图。 使用New Relic,开发者可以: 1. **实时性能监控**:New Relic的仪表板展示应用程序的...
2. **Symbol to_proc的优化**:Ruby 3.1对`Symbol#to_proc`进行了优化,提高了使用方法引用作为块时的性能。这在处理集合时特别有用,如`array.map(&:method)`。 3. **Ruby编译器改进**:内部编译器的优化使得代码...
- Ruby中的块(由`do...end`或`{...}`定义)是代码的可执行部分,可以与方法一起使用。Proc和Lambda是块的两种对象形式,它们可以保存并稍后执行。理解它们的差异,如 Proc的`call`和Lambda的`[]`调用方式,以及对...
例如,它会详细介绍如何创建和使用类、继承机制、模块混入、块和 Proc 对象,以及符号(Symbol)、字符串(String)、数组(Array)、哈希(Hash)等基本数据类型的使用。核心库的理解对于掌握Ruby语言至关重要。 ...
通过这个中文手册,开发者不仅可以学习到Ruby的基本语法,还可以了解到更高级的主题,如元编程、闭包、 Blocks、Proc对象和Symbol,以及如何利用Ruby的灵活性来创建高效、简洁的代码。同时,了解RGSS可以让开发者...
符号(Symbol)在Ruby中是特殊的,它们在内存中只存在一份,常用于元编程中的键值。 5. **Proc对象与lambda**:Ruby的`Proc`和`lambda`可以创建匿名函数,它们可以被赋值给变量,作为参数传递,或者用作方法的...
- 符号(Symbol)的高效利用。 - Lambda与Proc的区别。 5. **Ruby元编程** - 元编程是Ruby的核心优势之一。 - 动态创建方法和属性。 - 使用评估(Evaluation)和反射(Reflection)技术。 - 扩展和覆盖内置行为。 ...
在2.2.4中,引入了Symbol GC(垃圾回收),可以释放不再使用的Symbol,从而减少了内存占用。 此外,Ruby 2.2.4也引入了钻石问题的解决方案,这是在多重继承中可能出现的问题,即一个类可以从两个或更多拥有共同基类...
5. **Symbol到Proc转换的改进**:在Ruby 2.6.1中,使用`&:`操作符将符号转换为Proc更加高效,这在构建函数式编程模式时尤其有用。 6. **Ruby编译器选项**:这个版本增加了新的编译器选项,如`--enable-jit`(Just-...
7. **Symbol垃圾收集**:在Ruby 2.0之前,所有创建的Symbol都会永久存在内存中,但在2.0中,未使用的Symbol会被垃圾收集器回收,节省了内存。 8. **YARV虚拟机优化**:Ruby 2.0继续使用YARV(Yet Another Ruby VM)...
5. **符号(Symbol)**:Ruby引入了一种特殊的不可变对象——符号,用于表示唯一的标识符,节省内存。 6. **GVL(全局解释器锁)**:在Ruby 2.1.0版本中,虽然已经对GVL进行了优化,但仍然存在,这限制了并发执行的...
1. **变量和数据类型**:Ruby支持多种数据类型,包括整型(Integer)、浮点型(Float)、字符串(String)、布尔型(Boolean)以及符号(Symbol)。此外,Ruby还有数组(Array)和哈希(Hash)等复合数据类型。 2. ...
符号(Symbol) 符号是Ruby中的一种数据类型,它是一个不可变的字符串。在元编程中,符号经常被用作标识符来指代方法或属性,从而避免不必要的字符串创建。 **示例**: ```ruby def self.method_missing(name, *args...
这对于函数式编程风格的Ruby代码来说是个巨大的提升,尤其是在使用`Array#map`、`Array#select`等方法时。 ```ruby numbers = [1, 2, 3, 4] squared = numbers.map(&:square) # 使用 & 符号将 :square 转换为 Proc ...
7. **符号(Symbol)**:Ruby中的符号是不可变的,它们在内存中只存储一份,适用于作为哈希表的键,提高查找效率。 8. **块和 Proc**:Ruby中的块是代码的另一个形式,可以用`do..end`或者花括号`{}`包裹。Proc对象...
- **符号和哈希**:Ruby中的符号(Symbol)是一种不可变的数据类型,通常用于标识符或键值对中的键。哈希则是另一种强大的数据结构,常用于存储键值对。这两种数据类型的高效使用可以极大提高程序的性能和简洁性。 -...