寫這篇文章的初衷源於個人夥伴們在上手Ruby過程當中,表現實在是太讓人拙計了。因爲項目的急功近利,須要迅速入門Ruby並上手項目。因此不少開發者在實際開發過程當中,不熟悉Ruby的表達方式,也會沿用其餘語言比較生澀的表達形式。在我看來,Ruby的學習應該是個系統的按部就班的過程,儘可能避免急迫的方式。不過現實每每是緊迫的,因此就有了這篇文章。編程
標題中的菜鳥主要是指那些有其餘編程語言開發經驗,但在Ruby面前是個學習時間不久的初學者。個人工做夥伴都是這樣的一些人。因此,我就在考慮Ruby和其餘語言的一些顯著的不一樣點,想要提點他們注意這些地方,能將程序儘可能寫得Rubic。在我與其餘語言進行比較的過程當中,有了一些靈感,因此我就寫了點。後來靈感多了些,我也就多寫了些。設計模式
着重指出一點,沒有菜鳥開發者,只有停滯不前的開發者。系統學習一門語言才能自如地運用該語言的表達。Ruby的官方文檔是永遠是學習Ruby語言的最好資料,它最全面且持續更新。此外,Ruby的官方也給出了從其它語言到 Ruby的比較文檔。數組
在Java中,字符串只有雙引號的形式;在Python和JavaScript中,字符串既有單引號形式也有雙引號形式,但它們實踐是一回事。在Ruby的世界中,字符串的表達方式要豐富得多。Ruby中的字符串,既有單引號的形式,也有雙引號的形式,但它們的含義倒是大相徑庭的。ruby
單引號的字符串,指的是原生字符串,其中不含有轉義規則。例如'\n'
不是指換行符,而是指兩個字符的字符串,分別爲字符\\
和字符n
。閉包
雙引號的字符串,是包含轉義規則的。例如"\n"
就是指換行符。另外,雙引號的字符串還可使用#{...}
的方式嵌入表達式。less
"My Name is #{name}, and my years old is #{age}."
TODO 多行字符串編程語言
Ruby引入符號的概念,是源於Ruby的一個設計缺陷。在大部分語言設計中,字符串都設計爲不可變對象;然而在Ruby當中,字符串被設計爲可變的。爲此,引入了另外一個字符序列的類型,但它是不可變的。這就是符號(Symbol)。學習
Ruby中符號的寫法是在文本前面加上冒號(:)。對於Ruby中合法的變量名,直接加上冒號便可,例如:設計
:name :age :kind_of_animal
也能夠在字符串前面加上冒號,這時符號的內容能夠包含空格等變量名不容許的字符。示例:code
:"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.name
和a.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?
返回字符串是否爲空;sub
和sub!
方法替換字符串,區別是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爲假
其他都爲真
我懶!