Ruby菜鳥入門指南


寫這篇文章的初衷源於我的伙伴們在上手Ruby過程中,表現實在是太讓人拙計了。由於項目的急功近利,需要迅速入門Ruby並上手項目。所以很多開發者在實際開發過程中,不熟悉Ruby的表達方式,也會沿用其他語言比較生澀的表達形式。在我看來,Ruby的學習應該是個系統的循序漸進的過程,盡量避免急迫的方式。不過現實往往是緊迫的,所以就有了這篇文章。

標題中的菜鳥主要是指那些有其他編程語言開發經驗,但在Ruby面前是個學習時間不久的初學者。我的工作伙伴都是這樣的一些人。所以,我就在考慮Ruby和其他語言的一些顯著的不同點,想要提點他們注意這些地方,能將程序盡量寫得Rubic。在我與其他語言進行比較的過程中,有了一些靈感,所以我就寫了點。后來靈感多了些,我也就多寫了些。

着重指出一點,沒有菜鳥開發者,只有停滯不前的開發者。系統學習一門語言才能自如地運用該語言的表達。Ruby的官方文檔是永遠是學習Ruby語言的最好資料,它最全面且持續更新。此外,Ruby的官方也給出了從其它語言到 Ruby的比較文檔。

字符串

在Java中,字符串只有雙引號的形式;在Python和JavaScript中,字符串既有單引號形式也有雙引號形式,但它們實踐是一回事。在Ruby的世界中,字符串的表達方式要豐富得多。Ruby中的字符串,既有單引號的形式,也有雙引號的形式,但它們的含義卻是截然不同的。

單引號的字符串,指的是原生字符串,其中不含有轉義規則。例如'\n'不是指換行符,而是指兩個字符的字符串,分別為字符\\和字符n

雙引號的字符串,是包含轉義規則的。例如"\n"就是指換行符。另外,雙引號的字符串還可以使用#{...}的方式嵌入表達式。

"My Name is #{name}, and my years old is #{age}."

TODO 多行字符串

符號

Ruby引入符號的概念,是源於Ruby的一個設計缺陷。在大部分語言設計中,字符串都設計為不可變對象;然而在Ruby當中,字符串被設計為可變的。為此,引入了另一個字符序列的類型,但它是不可變的。這就是符號(Symbol)。

Ruby中符號的寫法是在文本前面加上冒號(:)。對於Ruby中合法的變量名,直接加上冒號即可,例如:

:name
:age
:kind_of_animal

也可以在字符串前面加上冒號,這時符號的內容可以包含空格等變量名不允許的字符。示例:

:"My Name is #{name}, and my years old is #{age}."

這里字符串的單引號和雙引號的性質也被沿用了下來。

符號是不可變的;並且,其是唯一的。對於內容完全相同的符號,其只會有一個實例存在於Ruby解釋器環境中。

TODO 相同內容符號的object_id一致

符號對於Hash的構造有特殊的作用。Ruby中,Hash的構造比較繁瑣,要用到=>符號:

{ 'a' => 'a', 'b' => 'b', 'c' => 'c' }

但是如果鍵值都是符號的話,有簡便的構造方法:

{ a: 'a', b: 'b', c: 'c' }

它等價於:

{ :a => 'a', :b => 'b', :c => 'c' }

由於在方法調用中最后一個Hash參數可以省略大括號,所以下面的調用

f({ a: 'a', b: 'b', c: 'c' })

可以去掉大括號,寫成:

f(a: 'a', b: 'b', c: 'c')

這就很像Python的關鍵字參數了。

最后,符號和字符串的相互轉化方式如下:

str.to_sym  #字符串轉化為符號
sym.to_s    #符號轉化為字符串

方法名是符號。

一切皆是對象

Java中有些基本數據類型(boolean、int、double),它們不是對象。JavaScript中的基本數據類型可以理解為對象,如boolean、number、string、function;但它們不能像普通的JS對象那樣自如地增刪屬性。Python要徹底些,一切皆是對象,包括數字和布爾值都是普通的對象。

不過,比起所有其他的語言,Ruby是貫徹一切皆是對象這一思想最徹底的語言。在Ruby中:

  • 數字、布爾值、字符串、數組是對象。

  • 類是對象,它是Class類的實例。

  • 指示對象不存在的nil值也是對象,它是NilClass的實例,可以調用方法to_s, to_i等。

一切皆是表達式

這可能是Ruby又一個玄妙的地方了,影射了Ruby大一統的設計理念。Ruby中一切皆是表達式,一切表達方式都返回值。

  • 普通的Ruby表達式當然返回值。

  • if、while等控制結構返回值,其值是內部最后一條語句的值。

  • 方法調用返回值,其值由return指定或者是方法內最后一條語句的值。

  • 類定義返回值,其值是類內部最后一條語句的值。

  • 方法定義返回值,其值是方法名表示的符號。

TODO 一切皆是表達式示例

一切皆是方法調用

Ruby是也是貫徹面向對象設計模式最徹底的語言。在面向對象的設計理念中,為了提升封裝性,會禁止直接的對象屬性操作,只給出相應的get和set方法。

而在Ruby中,從語言層級中就禁止了直接訪問對象屬性的途徑,只存在方法調用。我們平常常見的a.namea.name = 'Hello'的調用方式,看上去很像是直接操作屬性,其實不是的。因為Ruby的方法調用可以省略括號,所以

a.name

等價於

a.name()

a.name = 'Hello'

的形式,實際上是

a.name=('Hello')

的簡寫。

TODO attr_reader, attr_writer, attr_accessor宏

省略分號

TODO 省略分號

省略括號的方法調用

Ruby中的方法調用,可以省略括號:

f a, b, c

等價於:

f(a, b, c)

控制結構

TODO 控制結構:if-else,unless-else,when-case,while,begin-rescue-ensure

變量命名約定

面向對象語言中,根據作用域的不同,分別有全局變量、常量、類變量、實例變量、局部變量的區別。在其他的語言中,可能是通過不同的修飾符和作用域進行區別。例如在Java中,沒有全局變量的概念,常量用final修飾,類變量用static修飾,實例變量存在於類定義中,局部變量存在於方法定義中。有時候,這些變量很容易混淆;局部變量也很容易覆蓋掉實例變量和類變量。

在Ruby中,是以變量名的格式區別變量的類型。總結如下:

  • 局部變量:以小寫字母開頭

  • 常量:以大寫字母開頭

  • 實例變量:以@開頭

  • 類變量:以@@開頭

  • 全局變量:以$開頭

TODO 變量名示例

方法名約定

Ruby中的方法名結尾可以跟?和!。一般來說,以?結尾的方法返回布爾值;以!結尾的方法提示危險性。例如字符串中,empty?返回字符串是否為空;subsub!方法替換字符串,區別是sub不修改原字符串,返回替換的字符串;sub!作原地替換,會修改原字符串。

一般來講,返回布爾值的方法名以?結尾,會對原對象作潛在性的修改的方法名以!結尾。

Ruby中的方法不是一等公民。方法不是值,不能作為參數傳遞給另一個方法。不過Ruby有塊的概念,塊可以作為語言特性附加給方法調用。

塊的寫法有兩種形式,分別是大括號形式和do...end形式。

大括號形式:

{ |a, b|
    a.to_i <= b.to_i
}

do...end形式:

do |a, b|
    a.to_i <= b.to_i
end

乍一看,大括號的形式有點丑。一般來說,只在單行塊的時候用大括號的形式:

{ |a, b| a.to_i <= b.to_i }

Ruby中的每個方法都可以接受一個塊。塊要緊接着方法調用的后面,不是方法的參數之一。例如

f(1, 2, 3) do |a, b|
    a.to_i <= b.to_i
end

上面的示例中省略括號也是合法的:

f 1, 2, 3  do |a, b|
    a.to_i <= b.to_i
end

但像下面這樣把塊用括號括起來作為最后一個參數就是錯誤的:

f(1, 2, 3, { |a, b| a.to_i <= b.to_i }) #語法錯誤

塊與方法一個很大的區別是塊支持閉包:

min = 18

array.select do |v| 
    v >= min #訪問外層min變量 
end

TODO 在方法定義中用yield關鍵字調用塊

迭代器

Ruby中沒有提供Java和JavaScript當中三段for循環的模式。所謂三段for循環,是指下面JavaScript的for循環:

for(i = 0; i <= 9; i++) {
    console.log(i);
}

Ruby中沒有提供這樣的方式。但這並沒有什么痛苦的,因為Ruby提供了基於塊的迭代方式。例如上面的代碼,在Ruby中可以寫成:

0.upto(9) do |i|
    puts i
end

Ruby中的集合,都支持這樣傳遞代碼塊的迭代方式。Ruby中的集合包括Range、Array、Hash、String、etc。例如上面的示例可以改寫成Range的each迭代形式:

(0..9).each do |i| 
    puts i
end

TODO -ect方法:collect, inject, select

真假值

Ruby中用於if、unless、while的條件判斷中,真假值的規則很簡潔:

  • nil和false為假

  • 其余都為真

TODO list

我懶!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM