简介: 假设您是一名 C++ 开发人员,您需要使用 Ruby 快速执行一些原型设计。当您拿起一本 Ruby 参考书籍(比如 Pickaxe)或浏览 Ruby 网站时,会看到一些熟悉的构造,比如类声明、线程支持和异常处理。正当您认为自己了解 Ruby 的工作原理之时,您意识到了,您 Ruby 代码中的并发机制与 Boost 线程工作原理不一样,catch 和 throw 也与它们看上去的大不相同,而且其他人在其 Ruby 脚本中各处使用了名为 self 的关键词。欢迎来到 Ruby 的世界中!
如果您是一名 C++ 程序员且需要在 Ruby 环境中工作,那么您有一些功课要做。本文讨论了 Ruby 新手可能会误解的六个 Ruby 特性,特别是当他或她来自一个类似但又不太相同的环境,比如 C++:
● Ruby 类层次结构
● Ruby 中的单例方法
● self 关键词
● method_missing 方法
● 异常处理
● 线程
注意:本文中所有的代码均进行测试,且基于 Ruby 版本 1.8.7。
Ruby 中的类层次结构
Ruby 中的类层次结构会很棘手。创建一个 Cat 类型的类并开始探讨其层次结构(参见 清单 1)。
清单 1. Ruby 中的隐式类层次结构
irb(main):092:0> class Cat irb(main):093:1> end => nil irb(main):087:0> c = Cat.new => #<Cat:0x2bacb68> irb(main):088:0> c.class => Cat irb(main):089:0> c.class.superclass => Object irb(main):090:0> c.class.superclass.superclass => nil irb(main):091:0> c.class.superclass.superclass.superclass NoMethodError: undefined method `superclass' for nil:NilClass from (irb):91 from :0</div>
Ruby 中的所有对象(甚至用户定义的对象)都是 Object 类的后代,这在清单 1 中清晰可见。这与 C++ 是鲜明的对比。这一点也不像普通数据类型,例如 C/C++ int 或 double。清单 2 显示了整数 1 的类层次结构。
清单 2. 整数 1 的类层次结构
irb(main):100:0> 1.class => Fixnum irb(main):101:0> 1.class.superclass => Integer irb(main):102:0> 1.class.superclass.superclass => Numeric irb(main):103:0> 1.class.superclass.superclass.superclass => Object</div>
到目前为止一切顺利。现在您知道了类本身是 Class 类型的对象。而 Class 最终派生自 Object,如 清单 3 中所示使用 Ruby 内置的 String 类。
清单 3. 类的类层次结构
irb(main):100:0> String.class => Class irb(main):101:0> String.class.superclass => Module irb(main):102:0> String.class.superclass.superclass => Object</div>
Module 是 Class 的基类,但是使用它时有一点要注意,即您不能直接实例化用户定义的 Module 对象。如果您不想深入 Ruby 内部,最好考虑与 C++ 命名空间有类似特征的 Module:您可以定义您自己的方法、常量、等等。您在 Class 中包含了一个 Module,以及 voilà,Module 的所有元素现在会魔法般地成为 Class 的元素。清单 4 提供了一个示例。
清单 4. Module 不能进行直接实例化,并且只能与类一同使用
irb(main):020:0> module MyModule irb(main):021:1> def hello irb(main):022:2> puts "Hello World" irb(main):023:2> end irb(main):024:1> end irb(main):025:0> test = MyModule.new NoMethodError: undefined method `new' for MyModule:Module from (irb):25 irb(main):026:0> class MyClass irb(main):027:1> include MyModule irb(main):028:1> end => MyClass irb(main):029:0> test = MyClass.new => #<MyClass:0x2c18bc8> irb(main):030:0> test.hello Hello World => nil</div>
下面再重申一下重点:当您使用 Ruby 编写 c = Cat.new 时,c 是派生自 Object 的 Cat 类型的一个对象。Cat 类是 Class 类型的一个对象,Class 派生自 Module,而 Module 又派生自 Object。因此该对象及其类型都是有效的 Ruby 对象。
单例方法和可编辑类
现在,看一下单例方法。假设您想使用 C++ 建模类似于人类社会的东西。那么您会如何做呢?定义一个名为 Human 的类,然后定义数百万的 Human 对象?这更像是在建模一个呆板的社会;每个人必须具惟一的特征。Ruby 的单例方法在这里就派上了用场,如 清单 5 所示。
清单 5. Ruby 中的单例方法
irb(main):113:0> y = Human.new => #<Human:0x319b6f0> irb(main):114:0> def y.paint irb(main):115:1> puts "Can paint" irb(main):116:1> end => nil irb(main):117:0> y.paint Can paint => nil irb(main):118:0> z = Human.new => #<Human:0x3153fc0> irb(main):119:0> z.paint NoMethodError: undefined method `paint' for #<Human:0x3153fc0> from (irb):119</div>
Ruby 中的单例方法 是仅与特定对象关联的方法,不能用于一般的类。它们的前缀是对象名称。在 清单 5 中,paint 方法特定于 y对象,而且仅限于 y 对象;z.paint 导致一个 “方法未定义” 错误。您可以调用 singleton_methods 来查明一个对象中的单例方法列表:
irb(main):120:0> y.singleton_methods => ["paint"]</div>
不过在 Ruby 中有另一种定义单例方法的方式。看看 清单 6 中的代码。
清单 6. 创建单例方法的另一种方式
irb(main):113:0> y = Human.new => #<Human:0x319b6f0> irb(main):114:0> class << y irb(main):115:1> def sing irb(main):116:1> puts "Can sing" irb(main):117:1> end irb(main):118:1>end => nil irb(main):117:0> y.sing Can sing => nil</div>
清单 5 还开创了新的可能性,可以添加新方法到用户定义的类和内置的 Ruby 现有类,比如 String。这在 C++ 中是不可能实现的,除非您能够访问您使用的类的源代码。再次观察 String 类(清单 7)。
清单 7. Ruby 允许您修改一个现有的类
irb(main):035:0> y = String.new("racecar")
=> "racecar"
irb(main):036:0> y.methods.grep(/palindrome/)
=> [ ]
irb(main):037:0> class String
irb(main):038:1> def palindrome?
irb(main):039:2> self == self.reverse
irb(main):040:2> end
irb(main):041:1> end
irb(main):050:0> y.palindrome?
=> true
</div>
清单 7 清楚地展示了如何编辑一个现有的 Ruby 类来添加您自行选择的方法。这里,我添加了 palindrome? 方法到 String 类。因此 Ruby 类在运行时是可编辑的(一个强大的属性)。
现在您对 Ruby 的类层次结构和单例有了一定的认识,接下来我们来看 self。注意,在定义 palindrome? 方法时我使用了 self。
发现 self
self 关键词的最常见用法可能就是在 Ruby 类中声明一个静态方法,如 清单 8 所示。
清单 8. 使用 self 声明类的静态方法
class SelfTest def self.test puts "Hello World with self!" end end class SelfTest2 def test puts "This is not a class static method" end end SelfTest.test SelfTest2.test</div>
从 清单 8 的输出中可以看到(如 清单 9 所示),没有对象您无法调用非静态方法。该行为类似于 C++。
清单 9. 在没有对象的情况下调用非静态方法时会出错
irb(main):087:0> SelfTest.test Hello World with self! => nil irb(main):088:0> SelfTest2.test NoMethodError: undefined method 'test' for SelfTest2:Class from (irb):88</div>
在探讨 self 更深奥的用途和含义之前,注意您也可以通过在方法名称前面加上类名来在 Ruby 中定义一个静态方法:
class TestMe def TestMe.test puts "Yet another static member function" end end TestMe.test # works fine</div>
清单 10 提供了 self 的一个更有趣但不太容易找到的用法。
清单 10. 使用元类来声明静态方法
&nbs

