当你第一次看到一些 Ruby 代码时,它可能会让你想起你用过的其他编程语言。这是故意的。许多语法对于 Perl、Python 和 Java(以及其他语言)的用户来说都很熟悉,所以如果你用过这些语言,学习 Ruby 将轻而易举。
本文档包含两个主要部分。第一部分试图快速总结从语言X到 Ruby 的预期内容。第二部分讨论主要语言特性以及它们与你已经熟悉的语言的比较。
预期:从语言 X到 Ruby
重要的语言特性和一些注意事项
以下是一些关于学习 Ruby 时会遇到的主要 Ruby 特性的提示和建议。
迭代
Ruby 的两个特性与你之前可能见过的有些不同,需要一些时间来适应,它们是“块”和迭代器。与遍历索引(如 C、C++ 或 1.5 之前的 Java)或遍历列表(如 Perl 的 for (@a) {...}
或 Python 的 for i in aList: ...
)不同,在 Ruby 中,你经常会看到
有关 each
(及其朋友 collect
、find
、inject
、sort
等)的更多信息,请参阅 ri Enumerable
(然后 ri Enumerable#some_method
)。
一切都有值
表达式和语句之间没有区别。一切都有值,即使该值为 nil
。这是可能的
符号不是轻量级的字符串
许多 Ruby 新手难以理解符号是什么以及它们可以用来做什么。
符号最好被描述为身份。符号是关于它是谁,而不是它是什么。启动 irb
并查看区别
object_id
方法返回对象的标识。如果两个对象的 object_id
相同,则它们是相同的(指向内存中的同一个对象)。
正如您所见,一旦您使用过一个 Symbol,任何具有相同字符的 Symbol 都会引用内存中的同一个对象。对于任何两个代表相同字符的 Symbol,它们的 object_id
都会匹配。
现在看看字符串 (“george”)。它们的 object_id
不匹配。这意味着它们引用了内存中的两个不同对象。每当您使用一个新的字符串时,Ruby 都会为它分配内存。
如果您不确定是使用 Symbol 还是字符串,请考虑哪一个更重要:对象的标识(例如 Hash 键)还是内容(在上面的例子中是 “george”)。
万物皆对象
“万物皆对象”不仅仅是夸张的说法。即使是类和整数也是对象,您可以对它们执行与其他任何对象相同的操作。
变量常量
常量实际上并不恒定。如果您修改了一个已经初始化的常量,它会触发一个警告,但不会停止您的程序。但这并不意味着您应该重新定义常量。
命名约定
Ruby 强制执行一些命名约定。如果一个标识符以大写字母开头,它就是一个常量。如果它以美元符号 ($
) 开头,它就是一个全局变量。如果它以 @
开头,它就是一个实例变量。如果它以 @@
开头,它就是一个类变量。
然而,方法名允许以大写字母开头。这可能会导致混淆,如下面的例子所示。
现在 Constant
是 10,但 Constant()
是 11。
关键字参数
与 Python 一样,从 Ruby 2.0 开始,方法可以使用关键字参数定义。
普遍真理
在 Ruby 中,除了 nil
和 false
之外,所有内容都被认为是真值。在 C、Python 和许多其他语言中,0 和可能的其他值(如空列表)被认为是假值。请看以下 Python 代码(此示例也适用于其他语言)
这将打印 “0 is false”。等效的 Ruby 代码
打印 “0 is true”。
访问修饰符一直有效到作用域结束
在以下 Ruby 代码中,
您可能期望 another_method
是公开的。并非如此。private
访问修饰符一直有效到作用域结束,或者直到出现另一个访问修饰符,以先发生者为准。默认情况下,方法是公开的。
public
、private
和 protected
实际上是方法,因此它们可以接受参数。如果您向其中一个方法传递一个 Symbol,则该方法的可见性将被更改。
方法访问
在 Java 中,public
表示任何人都可以访问方法。 protected
表示该类的实例、子类实例以及同一包中的类实例可以访问它,但其他人则不能访问,而 private
表示除了该类的实例之外,没有人可以访问该方法。
Ruby 有些不同。 public
自然是公开的。 private
表示方法仅在没有显式接收者的情况下才能调用时才可访问。 只有 self
才能作为私有方法调用的接收者。
protected
是需要注意的。 受保护的方法可以从类或子类实例调用,也可以使用另一个实例作为其接收者。 以下是一个示例(改编自 Ruby 语言常见问题解答)
类是开放的
Ruby 类是开放的。 您可以随时打开它们、添加内容并更改它们。 即使是核心类,例如 Integer
甚至 Object
(所有对象的父类)。 Ruby on Rails 为 Integer
定义了一组用于处理时间的方法。 观看
有趣的方法名称
在 Ruby 中,方法允许以问号或感叹号结尾。 按照惯例,回答问题的 method 以问号结尾(例如 Array#empty?
,如果接收者为空,则返回 true
)。 按照惯例,潜在的“危险”方法以感叹号结尾(例如修改 self
或参数的方法,exit!
等)。 不过,并非所有更改其参数的方法都以感叹号结尾。 Array#replace
用另一个数组的内容替换数组的内容。 这样一种不修改 self 的方法没有多大意义。
单例方法
单例方法是每个对象的 method。 它们仅在您定义它的对象上可用。
缺少方法
如果 Ruby 找不到响应特定消息的方法,它不会放弃。 它会调用 method_missing
方法,并使用它找不到的方法的名称和参数。 默认情况下,method_missing
会引发 NameError 异常,但您可以重新定义它以更好地适应您的应用程序,许多库都会这样做。 以下是一个示例
上面的代码只是打印调用详细信息,但您可以自由地以任何合适的方式处理消息。
消息传递,而不是函数调用
方法调用实际上是向另一个对象发送的消息
块是对象,只是它们还没有意识到这一点
块(实际上是闭包)被标准库广泛使用。要调用块,您可以使用 yield
,或者通过在参数列表中追加一个特殊参数将其转换为 Proc
,如下所示
您也可以在方法调用之外创建块,方法是使用块调用 Proc.new
或调用 lambda
方法。
类似地,方法也是正在创建的对象
运算符是语法糖
Ruby 中的大多数运算符只是方法调用的语法糖(带有一些优先级规则)。例如,您可以重写 Integer 的 +
方法
您不需要 C++ 的 operator+
等。
如果您定义了 []
和 []=
方法,甚至可以进行数组式访问。要定义一元 + 和 -(例如 +1 和 -2),您必须分别定义 +@
和 -@
方法。但是,下面的运算符不是语法糖。它们不是方法,不能重新定义
此外,+=
、*=
等只是 var = var + other_var
、var = var * other_var
等的缩写,因此不能重新定义。
了解更多
当您准备好学习更多 Ruby 知识时,请查看我们的 文档 部分。