`
loamy
  • 浏览: 321455 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Ruby之Symbol

    博客分类:
  • ruby
阅读更多
在Ruby中symbol是Symbol类的实例。symbol的语法为一个冒号后面接一个标识符。

symbol就像一个字符串,它表示了一个字符序列。它不像字符串,每个symbol只有一个实例(和Fixnum一样)。因此,有一个内存或
性能问题需要弄清楚。例如,在下面的代码中,"foo"字符串以三个单独的对象存储在内存中,但是symbol :foo作为一个单独的对
象存储(被引用了多次):
代码

   1. array = ["foo", "foo", "foo", :foo, :foo, :foo] 

有些人被symbol前面的冒号弄糊涂了。其实没有必要糊涂;这只是一个简单的语法形式。字符串,数组和哈希都有开始和结束界定
符;而symbol只有一个开始界定符。把它当成一个单界定符而不是二元界定符即可。开始时你可能认为这个语法很奇怪,但事实上
没有什么神秘的。

值得注意的是在老版本的Ruby(1.6之前)中,symbol常量不是第一类对象而是转换成Fixnum来存储。现在在内核中这仍然是对的;
symbol对应于一个数字并作为一个immediate value来存储。这个值可以使用to_i来得到,但是没有必要。

根据Jim Weirich,symbol是"有名字的对象"。Austin Ziegler更喜欢说"an object that is a name"。无论怎样,在symbol和名字
间始终有一个一对一的对应。什么样的东西我们需要使用名字?例如变量,方法和任意的常量。

一个常见的symbol使用场景是表示变量或方法的名字。例如,我们知道如果我们想添加一个读/写属性到类中,我们可以这样做:
代码

   1. class SomeClass 
   2.    attr_accessor :whatever 
   3. end 


这等价于:
代码

   1. class SomeClass 
   2.    def whatever 
   3.     @whatever 
   4.    end 
   5.    def whatever=(val) 
   6.     @whatever = val 
   7.    end 
   8. end 


换句话说,:whatever这个symbol告诉attr_accessor方法"getter"和"setter(以及实例变量)都将根据该symbol来给予名字。

你可能想问为什么我们不能使用一个字符串来替代。我们可以。大部分希望使用symbol的核心方法都可以使用字符串来替代。
代码

   1. attr_reader :alpha 
   2. attr_reader "beta"    # This is also legal 

事实上,symbol就"像"一个字符串,它对应于一个字符序列。这导致有些人说"a symbol is just an immutalbe string"。
但是,Symbol类并不是继承于String,并且对于字符串典型的操作并不适合symbol。

另一个误解是认为symbol没必要直接对应于标识符。这导致有些人说"the symbol table"(as they would in referring to
an assembled object program)。但是这不是一个真正有用的概念;尽管在内部symbol存储在一种table里,Ruby并没有将
这个table作为一个实体暴露给我们访问,而我们作为编程者也不关心它的存在。

而且,symbol不需要看起来像标识符。虽然它们像标识符,但是它们也可以包含标点,如果它们被引号包围的话。如下也是
合法的Ruby symbol:
代码

   1. sym1 = :"This is a symbol" 
   2. sym2 = :"This is, too1" 
   3. sym3 = :")(*&^%$"              # and even this 


你甚至可以使用这些symbol来定义实例变量和方法,但是这样的话你需要send和instance_variable_get技术来引用它们。
一般来说不推荐使用字符串形式的symbol。

Symbols As Enumerations
Pascal以及后期版本的C等语言有一个enumerated type的概念。Ruby没有这样的东西;Ruby没有类型检查。但是symbol
非常有用;我可以用:north,:south,:east和:west来表示方向。

将这些symbol存储为常量可能更清晰。
代码

   1. North, South, East, West = :north, :south, :east, :west 


如果它们是字符串而不是symbol,将它们定义为常量会节省内存,但无论如何每个symbol都只在对象空间里存在一次。
(像Fixnum一样Symbol存储为immediate value)

Symbols As Metavalues
我们经常使用异常来作为避免返回代码的方式。但是如果你宁愿使用返回代码的话也可以。RUby的方法不限于单返回类型,
这让传回"out of band"值成为可能。

我们经常需要这样的值。ASCII NUL字符被认为根本就不是一个字符。C有NULL指针,Pascal有nil指针,SQL有NULL等等。
Ruby当然也有nil。

这些metavalue的问题是它们成为合法的值。现在每个人都认为NUL是一个ASCII字符。在Ruby中,nil不是真的non-object;
它可以被存储和操作。这样我们有了如hash[key]返回nil这样的小烦恼;是因为key没有找到而返回nil,还是由于这个key
真的指向nil?

这里symbol可以用来作为好的metavalue。假设一个方法从忘了攫取一个字符串(可能通过http或其他类似的东西)。我们可以
返回非字符串值来表示出现异常。
代码

   1. str = get_string 
   2. case str 
   3.    when String 
   4.      # Proceed normally 
   5.    when :eof 
   6.      # end of file, socket closed, whatever 
   7.    when :error 
   8.      # I/O or network error 
   9.    when :timeout 
  10.      # didn't get a reply 
  11. end 


这比使用异常更好或更清晰?没必要。但是记住,这是处理可能为"edge cases"但不一定是异常的条件时的一项技术。

Symbols, Variables, and Methods
可能使用symbol的最知名的地方是定义类的属性:
代码

   1. class MyClass 
   2.    attr_reader :alpha, :beta 
   3.    attr_writer :gamma, :delta 
   4.    attr_accessor :epsilon 
   5.    # ... 
   6. end 


attr_accessor使用symbol名字来觉得实例变量和读写方法的名字。这不代表symbol和实例变量名之间有绝对的关系。
例如,如果你使用instance_variable_set,我们必须指定变量的名字,包括@符号:
代码

   1. sym1 = :@foo 
   2. sym2 = :foo 
   3. instance_variable_set(sym1, "str")    # Works 
   4. instance_variable_set(sym2, "str")    # errors 


简短来说,传递到attr系列方法的symbol只是一个参数,这些方法基于symbol的值创建需要的实例变量和方法。(writer方法
在结尾有一个=,而实例变量名字在前面有一个@。)换句话说,symbol必须与它引用的标识符相对应。

大部分情况下,希望使用symbol的方法也可以使用字符串。相反则不一定正确。

Converting to/from Symbols
字符串和symbol可以使用to_s和to_sym方法自由互换:
代码

   1. a = "foobar" 
   2. b = :foobar 
   3. a == b.to_s    # true 
   4. b == a.to_sym    # true 


如果你做元编程,如下方法有时候可能很有用。
代码

   1. class Symbol 
   2.    def +(other) 
   3.      (self.to_s + other.to_s).to_sym 
   4.    end 
   5. end 


上面的方法允许我们连接symbol(或者添加字符串到一个symbol)。下面是一个使用它的例子;这段微小的代码接收一个symbol并
尝试告诉我们它是否是一个accessor(即,读写方法都存在):
代码

   1. class Object 
   2.    def accessor?(sym) 
   3.     return (self.respond_to?(sym) and self.respond_to?(sym+"=")) 
   4.    end 
   5. end 


我这里要提到一个使用symbol的聪明的方式。当我们做map操作时,有时候一个复杂的block可能附加在后面。但是许多情况下,
我们对每个元素简单的调用一个方法:
代码

   1. list = words.map { |x| x.capitalize } 


在这里,似乎我们为完成工作做了太多事情。让我们打开Symbol类并定义to_proc方法。这保证任何symbol都可以强制转换成
一个proc对象。但是我们应该返回什么proc?显然应该根据对象context里的symbol本身。换句话说,proc应该将symbol本身作
为一个消息发送给对象。
代码

   1. def to_proc 
   2.    proc { |obj, *args| obj.send(self, *args) } 
   3. end 


顺便提一下,这段代码来自Gavin Sinclair的"Ruby Extensions"对象。有了这个方法,我们可以重写上面的代码:
代码

   1. list = words.map(&:capitalize) 


值得花费一分钟来理解它怎样工作。map方法使用一个block作为参数。&符号允许我们传递一个proc而不是一个显式附加的
block。由于我们在一个非proc对象上使用&符号,解释器会尝试调用该对象的to_proc方法。返回的proc替代了显式的block,
map将会对每个元素调用它。为什么self作为一个消息传递给array元素有意义呢?这是因为proc是一个闭包,所以它会记住
它被创建在哪个context里。当它被创建时,self表示调用to_proc的symbol。
分享到:
评论
1 楼 blackanger 2008-10-14  
把the ruby way的内容搬上来也没什么意义

相关推荐

    符号的优雅:深入探索Ruby中的Symbol

    符号不仅是 Ruby 性能优化的关键组成部分,也是理解 Ruby 核心特性的窗口之一。通过深入了解符号的特性和使用方式,我们可以更好地利用它们来编写更加高效和 Ruby 风格的代码。 #### 符号概述 符号是 Ruby 中一种...

    比较详细的ruby symbol 学习资料

    解释的不错,应该明确了不少 ruby symbol详解 起因 最近在学习ruby on rails,的确是一个优秀的数据库开发框架。但在过程中,发现在视图文件夹中的rhtml文件里有大量的类似于以下的语句: <td><%= link_...

    Ruby资源ruby-v3.1.1.zip

    2. **Symbol to_proc的优化**:Ruby 3.1对`Symbol#to_proc`进行了优化,提高了使用方法引用作为块时的性能。这在处理集合时特别有用,如`array.map(&:method)`。 3. **Ruby编译器改进**:内部编译器的优化使得代码...

    ruby官方chm文档

    Ruby允许在运行时修改代码,这使得元编程成为其强大之处。理解如何使用`eval`、`class_eval`和`instance_eval`,以及如何利用`send`和`method_missing`进行消息传递,是提升Ruby编程技巧的关键。 《ruby23.chm》...

    Ruby元编程第二版中文

    在Ruby中,元编程的强大之处在于其语法简洁且易于理解,使得程序员可以轻松地实现动态行为。Ruby提供了多种元编程工具,包括: 1. **方法定义与调用**:Ruby允许在运行时定义和修改方法,如`define_method`函数可以...

    ruby中文手册 chm

    通过这个中文手册,开发者不仅可以学习到Ruby的基本语法,还可以了解到更高级的主题,如元编程、闭包、 Blocks、Proc对象和Symbol,以及如何利用Ruby的灵活性来创建高效、简洁的代码。同时,了解RGSS可以让开发者...

    eloquent ruby

    - 元编程是Ruby的核心优势之一。 - 动态创建方法和属性。 - 使用评估(Evaluation)和反射(Reflection)技术。 - 扩展和覆盖内置行为。 6. **测试与调试** - Ruby提供了丰富的测试框架,如RSpec和Test::Unit等。 ...

    ruby-2.2.4

    在Ruby 2.2.4中,最重要的更新之一是对Symbol的内存管理进行了优化。Symbol是Ruby中的特殊数据类型,它们是不可变的,并且在程序的生命周期内保持唯一。在之前的版本中,每个创建的Symbol都会消耗一定的内存,这在...

    Ruby-NewRelic找到并修复Ruby错误使用NewRelic的应用程序监控和故障诊断

    Ruby是一种流行的开源编程语言,以其简洁、优雅的语法和强大的元编程能力著称。在开发复杂的Web应用程序时,性能监控和故障诊断是确保系统稳定性和高效运行的关键环节。New Relic是一个强大的应用性能管理(APM)...

    learning-ruby.

    11. **Ruby on Rails框架**:虽然"learning-ruby"主要针对语言基础,但了解Ruby最流行的Web开发框架Rails也是有帮助的,因为它展示了Ruby在实际应用中的强大之处。 通过这个文档集,读者应该能逐步理解并掌握这些...

    ruby2.6.1.zip

    5. **Symbol到Proc转换的改进**:在Ruby 2.6.1中,使用`&:`操作符将符号转换为Proc更加高效,这在构建函数式编程模式时尤其有用。 6. **Ruby编译器选项**:这个版本增加了新的编译器选项,如`--enable-jit`(Just-...

    ruby trap 初学者使用

    2. **符号(Symbol)**: - 符号是Ruby中的一种特殊数据类型,它们是不可变的,常用于哈希键和方法调用。理解符号与字符串的区别对于优化内存使用至关重要。 3. **块和 Proc/Lambda**: - Ruby中的块(由`do......

    ruby-2.0.0-p0.tar

    7. **Symbol垃圾收集**:在Ruby 2.0之前,所有创建的Symbol都会永久存在内存中,但在2.0中,未使用的Symbol会被垃圾收集器回收,节省了内存。 8. **YARV虚拟机优化**:Ruby 2.0继续使用YARV(Yet Another Ruby VM)...

    ruby metaprograming

    符号(Symbol) 符号是Ruby中的一种数据类型,它是一个不可变的字符串。在元编程中,符号经常被用作标识符来指代方法或属性,从而避免不必要的字符串创建。 **示例**: ```ruby def self.method_missing(name, *args...

    ruby程序安装文件

    5. **符号(Symbol)**:Ruby引入了一种特殊的不可变对象——符号,用于表示唯一的标识符,节省内存。 6. **GVL(全局解释器锁)**:在Ruby 2.1.0版本中,虽然已经对GVL进行了优化,但仍然存在,这限制了并发执行的...

    二十分钟Ruby入门教程

    Ruby有几种基本的数据类型,包括整数(如`5`)、浮点数(如`3.14`)、字符串(用引号括起来,如`"Hello"`,支持单引号和双引号两种)、布尔值(`true`或`false`)以及符号(以冒号开头,如`:symbol`)。另外,数组和...

    ruby-2.3.0

    在Ruby-2.3.0中,最重要的更新之一是引入了“双尖括号解构赋值"(Double-quoted string interpolation with #{...})。这一特性允许开发者在字符串字面量中使用#{...}语法来嵌入表达式的值,使得代码更加简洁和可读...

Global site tag (gtag.js) - Google Analytics