当您初次看到 Ruby 语言代码的时候，它很可能让您想起您使用过的其他编程语言。这是当然的， 因为 Ruby 的大部分语法是
Perl、Python 和 Java（以及其他语言）的用户所熟悉的。 如果您曾经使用过这这些语言，学习 Ruby 就是小菜一碟。

本文包含了两部分。第一部分简明扼要地概述了当你从 *X* 到 Ruby 语言的一些所见所闻； 第二部分介绍了 Ruby 语言主要特性以及与你所熟悉的语言之间的差异。

## 可以期待什么: *从语言 X* 到 Ruby

* [从 C/C++ 到 Ruby](to-ruby-from-c-and-cpp/)
* [从 Java 到 Ruby](to-ruby-from-java/)
* [从 Perl 到 Ruby](to-ruby-from-perl/)
* [从 PHP 到 Ruby](to-ruby-from-php/)
* [从 Python 到 Ruby](to-ruby-from-python/)

## 重要的语言特性和一些小技巧

这里介绍了学习 Ruby 语言时应该注意的 Ruby 语言的特性。

### 迭代器

代码块和迭代是 Ruby 语言和其他语言不太一样的地方。我们可以以索引做循环（比如 C, C++, 或者 1.5 版本以前的
Java），或者以列表做循环（比如 Perl 的 `for (@a) {...}`， 还有 Python 的
`for i in aList: ...`），但是在 Ruby 中，我们常会看到

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">some_list</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">this_item</span><span class="o">|</span>
  <span class="c1"># 我们在代码块内内部。</span>
  <span class="c1"># 使用 this_item。</span>
<span class="k">end</span></code></pre></figure>

关于更多 `each`（还有 `collect`、`find`、`inject`、`sort` 等）的信息，请参考
`ri Enumerable` （和 `ri Enumerable#some_method`）。

### 一切表达方法皆有值

表达式和语句没有区别。任何表达方法都有返回值，即使那个值是 **nil**，比如下面的用法：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">x</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">11</span>
<span class="n">z</span> <span class="o">=</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">y</span>
      <span class="kp">true</span>
    <span class="k">else</span>
      <span class="kp">false</span>
    <span class="k">end</span>
<span class="n">z</span> <span class="c1"># =&gt; true</span></code></pre></figure>

### 符号不是轻量的字符串

很多 Ruby 初学者都在想办法搞清楚什么是符号和怎么使用符号。

符号最好的描述是身份证。一个符号代表了它是“谁”，而不是代表了它是“什么”。 打开 `irb` 来看一看他们的区别：

<figure class="highlight"><pre><code class="language-irb" data-lang="irb"><span class="gp">irb(main):001:0&gt;</span><span class="w"> </span><span class="ss">:george</span><span class="p">.</span><span class="nf">object_id</span> <span class="o">==</span> <span class="ss">:george</span><span class="p">.</span><span class="nf">object_id</span>
<span class="p">=&gt;</span> <span class="kp">true</span>
<span class="gp">irb(main):002:0&gt;</span><span class="w"> </span><span class="s2">"george"</span><span class="p">.</span><span class="nf">object_id</span> <span class="o">==</span> <span class="s2">"george"</span><span class="p">.</span><span class="nf">object_id</span>
<span class="p">=&gt;</span> <span class="kp">false</span>
<span class="gp">irb(main):003:0&gt;</span></code></pre></figure>

`object_id` 函数返回的是对象的身份标识。如果两个对象有相同的 `object_id`， 那么他们就是相同的（指向同一个内存地址）。 可以看出，当符号在使用过一次后，任何相同字符的符号都会在内存中指向同一个对象地址。 也就是说任何相同字符的符号的 `object_id`
都是相同的。

(“george”)的字符串的 `object_id` 并不相同，这表示他们在内存种指向不同对象地址。 每当您创建一个新的字符串的时候，Ruby
会在内存中为它分配新的空间。

当您犹豫该用符号还是字符串的时候，想一下究竟字符的标识更重要（比如 Hash key）还是内容更重要 （比如前面例子里的 “george” ）。

### 一切皆是对象

“一切皆是对象”并不是夸张。即使是类和整型变量也都是对象，您可以想使用其他对象一样使用他们：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># 等同于</span>
<span class="c1"># class MyClass</span>
<span class="c1">#   attr_accessor :instance_var</span>
<span class="c1"># end</span>
<span class="no">MyClass</span> <span class="o">=</span> <span class="no">Class</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
  <span class="nb">attr_accessor</span> <span class="ss">:instance_var</span>
<span class="k">end</span></code></pre></figure>

### 可以改变的常量

常量并不是真正恒定的。如果您修改了一个已初始化的常量，会触发警告，但程序不会中止。 当然这也不是说您“**应该**”改变常量。

### 命名约定

Ruby 强制了一些命名约定。大写字母开头的是一个常量；美元符号(`$`)开头的是全局变量； `@` 开头的是实例变量； `@@` 开头的是类变量。 然而函数的名字却可以大写字母开头。这可能会导致一些混淆，比如下面的例子：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Constant</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">def</span> <span class="nf">Constant</span>
  <span class="mi">11</span>
<span class="k">end</span></code></pre></figure>

这里 `Constant` 是 10，而 `Constant()` 是 11。

### 关键字参数

类似 Python, 从 Ruby 2.0 开始，可以使用关键字参数定义方法

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">deliver</span><span class="p">(</span><span class="ss">from: </span><span class="s2">"A"</span><span class="p">,</span> <span class="ss">to: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">via: </span><span class="s2">"mail"</span><span class="p">)</span>
  <span class="s2">"Sending from </span><span class="si">#{</span><span class="n">from</span><span class="si">}</span><span class="s2"> to </span><span class="si">#{</span><span class="n">to</span><span class="si">}</span><span class="s2"> via </span><span class="si">#{</span><span class="n">via</span><span class="si">}</span><span class="s2">."</span>
<span class="k">end</span>

<span class="n">deliver</span><span class="p">(</span><span class="ss">to: </span><span class="s2">"B"</span><span class="p">)</span>
<span class="c1"># =&gt; "Sending from A to B via mail."</span>
<span class="n">deliver</span><span class="p">(</span><span class="ss">via: </span><span class="s2">"Pony Express"</span><span class="p">,</span> <span class="ss">from: </span><span class="s2">"B"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"A"</span><span class="p">)</span>
<span class="c1"># =&gt; "Sending from B to A via Pony Express."</span></code></pre></figure>

### 通用真值

Ruby 把任何不是 **nil** 和 **false** 的值当作真值。在 C，Python 和其他语言里，0 和一些其他的值，
比如空的列表，会被当作假值。看一看下面的 Python 代码（这个例子也可以被应用到其他语言）：

<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c1"># Python 中
</span><span class="k">if</span> <span class="mi">0</span><span class="p">:</span>
  <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">0 为真</span><span class="sh">"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
  <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">0 为假</span><span class="sh">"</span><span class="p">)</span></code></pre></figure>

这会打印出 “0 为假”，而在 Ruby 中：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># Ruby 中</span>
<span class="k">if</span> <span class="mi">0</span>
  <span class="nb">puts</span> <span class="s2">"0 为真"</span>
<span class="k">else</span>
  <span class="nb">puts</span> <span class="s2">"0 为假"</span>
<span class="k">end</span></code></pre></figure>

会打印出 “0 为真”。

### 权限声明应用至作用域底部

下面的 Ruby 代码中，

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">MyClass</span>
  <span class="kp">private</span>
  <span class="k">def</span> <span class="nf">a_method</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>
  <span class="k">def</span> <span class="nf">another_method</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

您可能认为 `another_method` 是公有的。并不是这样的，“private” 权限声明会一直应用到类声明底部，
或者直到另外一个权限声明开始起作用。函数默认是公开的：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">MyClass</span>
  <span class="c1"># a_method 为公有</span>
  <span class="k">def</span> <span class="nf">a_method</span><span class="p">;</span> <span class="kp">true</span><span class="p">;</span> <span class="k">end</span>

  <span class="kp">private</span>

  <span class="c1"># another_method 为私有</span>
  <span class="k">def</span> <span class="nf">another_method</span><span class="p">;</span> <span class="kp">false</span><span class="p">;</span> <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

`public`、`private` 和 `protected` 其实都是方法， 所以他们可以接受参数。如果您给他们传递一个符号的话，那么符号所代表的函数的可见性会被改变。

### 函数访问

在 Java 里，`public` 表示方法可以被任何人访问。`protected` 表示此类实例、继承此类的实例及在同一个包内的所有类的实例可以访问，其他人则不能。`private` 表示任何此类实例外的人都不能访问。

Ruby 有些不同。`public` 还是公开的。`private` 表示只有非明确指定接收者（receiver）才允许调用。私有方法调用只允许 **self** 为接收者。

`protected` 应该特别注意。受保护的方法可以被类及继承类的实例调用，同一个类的其他实例也可以调用。 来自[Ruby Language FAQ][faq] 的例子:

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Test</span>
  <span class="c1"># 默认公开</span>
  <span class="k">def</span> <span class="nf">identifier</span>
    <span class="mi">99</span>
  <span class="k">end</span>

  <span class="k">def</span> <span class="nf">==</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
    <span class="n">identifier</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="nf">identifier</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">=</span> <span class="no">Test</span><span class="p">.</span><span class="nf">new</span>  <span class="c1"># =&gt; #&lt;Test:0x34ab50&gt;</span>
<span class="n">t2</span> <span class="o">=</span> <span class="no">Test</span><span class="p">.</span><span class="nf">new</span>  <span class="c1"># =&gt; #&lt;Test:0x342784&gt;</span>
<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>       <span class="c1"># =&gt; true</span>

<span class="c1"># 修改 `identifier' 为受保护方法，仍然可用</span>
<span class="c1"># 因为受保护方法允许其他引用</span>

<span class="k">class</span> <span class="nc">Test</span>
  <span class="kp">protected</span> <span class="ss">:identifier</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>  <span class="c1"># =&gt; true</span>

<span class="c1"># 修改 `identifier' 为私有方法</span>

<span class="k">class</span> <span class="nc">Test</span>
  <span class="kp">private</span> <span class="ss">:identifier</span>
<span class="k">end</span>

<span class="n">t1</span> <span class="o">==</span> <span class="n">t2</span>
<span class="c1"># NoMethodError: private method `identifier' called for #&lt;Test:0x342784&gt;</span></code></pre></figure>

### 类是开放的

Ruby 的类是开放的。任何时候你都可以打开它进行增加和修改。即使像 `Integer` 这样的核心类，甚至是所有对象的父类 `Object` 类都可以打开。Ruby on Rails 在 `Fixnum` 类里定义了一大堆方法来处理时间问题。请看：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Integer</span>
  <span class="k">def</span> <span class="nf">hours</span>
    <span class="nb">self</span> <span class="o">*</span> <span class="mi">3600</span> <span class="c1"># 一小时有多少秒</span>
  <span class="k">end</span>
  <span class="k">alias</span> <span class="n">hour</span> <span class="n">hours</span>
<span class="k">end</span>

<span class="c1"># 一月一号之后的 14 个小时</span>
<span class="c1"># （也就是你醒来的时间）</span>
<span class="no">Time</span><span class="p">.</span><span class="nf">mktime</span><span class="p">(</span><span class="mi">2006</span><span class="p">,</span> <span class="mo">01</span><span class="p">,</span> <span class="mo">01</span><span class="p">)</span> <span class="o">+</span> <span class="mi">14</span><span class="p">.</span><span class="nf">hours</span> <span class="c1"># =&gt; Sun Jan 01 14:00:00</span></code></pre></figure>

### 有趣的方法名

Ruby 的方法名允许以问号或感叹号结尾。习惯上，以问号结尾的方法返回布尔值（如：如果接收者为空的话 `Array#empty?` 返回 **true** ）。潜在“危险”方法（如修改 **self** 或参数的方法，`exit!` 等）以感叹号结尾。也不是所有修改参数的方法以感叹号结尾。 比如 `Array#replace` 方法将当前列表替换成另一个列表。毕竟这些方法就是为此而生的，**不修改**自身就没什么意义了。

### 单例方法（Singleton methods）

单例方法是单一对象方法。只在定义过的对象上可用。

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Car</span>
  <span class="k">def</span> <span class="nf">inspect</span>
    <span class="s2">"Cheap car"</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="n">porsche</span> <span class="o">=</span> <span class="no">Car</span><span class="p">.</span><span class="nf">new</span>
<span class="n">porsche</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Cheap car</span>
<span class="k">def</span> <span class="nc">porsche</span><span class="o">.</span><span class="nf">inspect</span>
  <span class="s2">"Expensive car"</span>
<span class="k">end</span>

<span class="n">porsche</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Expensive car</span>

<span class="c1"># 其他对象不受影响</span>
<span class="n">other_car</span> <span class="o">=</span> <span class="no">Car</span><span class="p">.</span><span class="nf">new</span>
<span class="n">other_car</span><span class="p">.</span><span class="nf">inspect</span> <span class="c1"># =&gt; Cheap car</span></code></pre></figure>

### Missing 方法

针对不存在的方法，Ruby 同样会进行处理。它会将这个不存在的方法名作为参数传递给 `method_missing`。`method_missing` 默认会抛出一个 NameError 异常，可以根据你的应用场景重新定义这个方法，许多库都是这么做的。看下面这个例子：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># id 是被调用的方法，* 号语法将所有参数收集到 "arguments" 数组内</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="o">*</span><span class="n">arguments</span><span class="p">)</span>
  <span class="nb">puts</span> <span class="s2">"调用了不存在的方法：</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">。它的参数：</span><span class="si">#{</span><span class="n">arguments</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">", "</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>

<span class="n">__</span> <span class="ss">:a</span><span class="p">,</span> <span class="ss">:b</span><span class="p">,</span> <span class="mi">10</span>
<span class="c1"># =&gt; 调用了不存在的方法：__。它的参数：a, b, 10</span></code></pre></figure>

上面的代码会打印出调用细节，你也可以选择任何适当的方式处理这个消息。

### 消息传递，非函数调用

方法调用实际将一条 **消息** 传递给另一个对象：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># 这个</span>
<span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
<span class="c1"># 跟下面这一样</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">+</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c1"># 跟下面这个也一样</span>
<span class="mi">1</span><span class="p">.</span><span class="nf">send</span> <span class="s2">"+"</span><span class="p">,</span> <span class="mi">2</span></code></pre></figure>

### 代码块也是对象，只是它们自己还不知道

代码块（实际是闭包）广泛应用于标准库。可以使用 `yield` 调用一个代码块，或者像下面这样，通过一个特殊的参数将它变为一个 `Proc`：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">block</span><span class="p">(</span><span class="o">&amp;</span><span class="n">the_block</span><span class="p">)</span>
  <span class="c1"># 这里，the_block 是被传递进来的代码块</span>
  <span class="n">the_block</span> <span class="c1"># 返回这个代码块</span>
<span class="k">end</span>
<span class="n">adder</span> <span class="o">=</span> <span class="n">block</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">|</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="p">}</span>
<span class="c1"># adder 现在是一个 Proc 对象</span>
<span class="n">adder</span><span class="p">.</span><span class="nf">class</span> <span class="c1"># =&gt; Proc</span></code></pre></figure>

调用 `lambda` 或 `Proc.new` 均可在方法外部创建代码块。

方法同样也是对象。

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="nb">method</span><span class="p">(</span><span class="ss">:puts</span><span class="p">).</span><span class="nf">call</span> <span class="s2">"puts 是一个对象!"</span>
<span class="c1"># =&gt; puts 是一个对象!</span></code></pre></figure>

### 操作符是语法糖

Ruby 中的大部分操作符仅仅是方法调用（根据一些优先级）的语法糖。例如，你可以覆盖 Integer 的 + 方法：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Integer</span>
  <span class="c1"># 请不要这么做，虽然你可以</span>
  <span class="k">def</span> <span class="nf">+</span><span class="p">(</span><span class="n">other</span><span class="p">)</span>
    <span class="nb">self</span> <span class="o">-</span> <span class="n">other</span>
  <span class="k">end</span>
<span class="k">end</span></code></pre></figure>

你不需要 C++ 的 `operator+` 等。

定义了 `[]` 和 `[]=` 方法后，你甚至拥有了数组风格的访问方法。要想定义一元操作符 + 和 -,你也必须定义相应的 `+@` 和 `-@` 方法。下面的操作符 **不是** 语法糖，它们不是方法，无法重新被定义：

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o">=</span><span class="p">,</span> <span class="o">..</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="ow">not</span><span class="p">,</span> <span class="o">&amp;&amp;</span><span class="p">,</span> <span class="ow">and</span><span class="p">,</span> <span class="o">||</span><span class="p">,</span> <span class="ow">or</span><span class="p">,</span> <span class="o">::</span></code></pre></figure>

此外，`+=`、`*=` 等类似操作符只是 `var = var + other_var`、 `var = var * other_var`等的简写。因此也无法重新被定义。

## 查找更多资料

当你准备学习更多 Ruby 知识的时候，请查看[文档](/zh_cn/documentation/)部分。



[faq]: http://ruby-doc.org/docs/ruby-doc-bundle/FAQ/FAQ.html
