当您第一次看到一些 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
,则它们是相同的(指向内存中的同一个对象)。
如您所见,一旦您使用过一次符号,任何具有相同字符的符号都引用内存中的同一个对象。对于任何两个表示相同字符的符号,object_id
是匹配的。
现在看一下字符串 (“george”)。object_id
不匹配。这意味着它们引用内存中的两个不同对象。每当您使用新字符串时,Ruby 都会为其分配内存。
如果您不确定是使用符号还是字符串,请考虑哪个更重要:对象的身份(即哈希键)还是内容(在上面的示例中为“george”)。
一切都是对象
“一切都是对象”不仅仅是夸张。即使是类和整数也是对象,您也可以像对待任何其他对象一样对它们执行相同的操作
可变的常量
常量实际上不是常量。如果您修改已初始化的常量,则会触发警告,但不会停止您的程序。但这并不是说您应该重新定义常量。
命名约定
Ruby 强制执行一些命名约定。如果标识符以大写字母开头,则它是一个常量。如果它以美元符号 ($
) 开头,则它是一个全局变量。如果它以 @
开头,则它是一个实例变量。如果它以 @@
开头,则它是一个类变量。
但是,允许方法名称以大写字母开头。这可能会导致混淆,如下面的示例所示
现在 Constant
是 10,但 Constant()
是 11。
关键字参数
与 Python 类似,自 Ruby 2.0 起,可以使用关键字参数定义方法
普遍的真理
在 Ruby 中,除了 nil
和 false
之外的所有内容都被视为 true。在 C、Python 和许多其他语言中,0 和其他可能的值(例如空列表)被视为 false。请查看以下 Python 代码(该示例也适用于其他语言)
这将打印 “0 is false”。等效的 Ruby 代码
打印 “0 is true”。
访问修饰符应用到作用域结束
在以下 Ruby 代码中,
您可能会期望 another_method
是公共的。事实并非如此。private
访问修饰符会持续到作用域结束,或者直到另一个访问修饰符出现为止,以先到者为准。默认情况下,方法是公共的
public
、private
和 protected
实际上是方法,因此它们可以接受参数。如果您将符号传递给其中一个,则该方法的可见性将被更改。
方法访问
在 Java 中,public
表示任何人都可访问该方法。protected
表示该类的实例、后代类的实例以及同一包中的类的实例可以访问该方法,但其他人都不能访问,而 private
表示除了该类的实例之外,没有人可以访问该方法。
Ruby 略有不同。public
自然是公共的。private
表示只有在可以在没有显式接收器的情况下调用方法时才能访问该方法。只有 self
才能成为私有方法调用的接收器。
protected
是需要注意的一个。可以从类或后代类实例调用受保护的方法,但也可以使用另一个实例作为其接收器。这是一个示例(改编自 Ruby 语言常见问题解答)
类是开放的
Ruby 类是开放的。您可以随时打开它们、向其中添加内容和更改它们。即使是核心类,例如 Integer
甚至 Object
(所有对象的父类)。Ruby on Rails 在 Integer
上定义了一堆用于处理时间的方法。请看
有趣的方法名称
在 Ruby 中,允许方法以问号或感叹号结尾。按照惯例,回答问题的方法以问号结尾(例如,Array#empty?
,如果接收器为空,则返回 true
)。按照惯例,潜在的“危险”方法以感叹号结尾(例如,修改 self
或参数的方法、exit!
等)。但是,并非所有更改其参数的方法都以感叹号结尾。Array#replace
将数组的内容替换为另一个数组的内容。有一个这样的方法而不修改 self 并没有多大意义。
单例方法
单例方法是每个对象的方法。它们仅在您定义它的对象上可用。
缺少的方法
如果 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 知识时,请参阅我们的文档部分。