2008年4月29日 星期二

Ruby初試心得2

繼續上面那邊之後,又繼續寫了一些題目。前面這邊就來講一些比較小的重點吧~

>> <<
首先呢,是ruby的位元運算子是 >> 或是 <<,而其方向性就是代表左移或是右移。在數字的型態下可以很簡單的算出某數乘以2的n次方後的值。而同樣的符號用在陣列或是字串則是代表在尾端插入或是移出幾個元素,不過跟數字不同的是,因為陣列或是字串都是為指標,所以會造成變數值的改變。(也就是說,arr = [], 現在我想要取得比多幾個元素,arr2 = arr[] << "test" -> arr2 = ["test"], arr = ["test])如果想要避免這種情況,用+運算子會較恰當。

空白 ()
ruby不是style free的語言(好像也沒聽過有人說過),他對空白(white space)老實說很明顯的是sensitive。舉個例子 i = str.length -1這個statement是不合語法的,你可以在-號前後都加空白,或是只在後面加空白,但是就是不能只加在前面。有時候會遇到莫名其妙的編譯錯誤, 這時候請嘗試檢查一些步必要的空白,有時候就可以過了~"~。類似的情形還有(),在ruby方法後面的參數你可以選擇像一般語言使用()來傳遞,也可以用個空白來代替這樣的語法來增加可讀性。像是 my_score.is_greater_than your_score。不過在參數一多,或是方法中的參數有方法的時候,這樣的式子小則出現warning,大則無法通過編譯。所以..除了是非常簡明的方法外,盡量要少用這樣的語法。

Enumerable
重點來了,for each語法在ruby中算的上簡單又實用的語法,在實做圖論的一些演算法的時候,for each node in graph這樣虛擬碼,跟ruby語法幾乎沒兩樣。不過要實做他,必須包含Enumerable 此模組。當初看到的時候,是在是有點開心,可以這麼簡單就實做出來,不過是令苦惱的是說明文件上的一段話:The class must provide a method each, which yields successive members of the collection. 我知道要提供一個each方法讓他提供其他實做,問題是,那each裡面到底要寫些啥好?是丟出一個陣列還是也丟出一個each?在多方查詢之後...最後還是找到ruby論壇,裡面雖然沒有找到有人問過相同問題,不過也是看到的人家是如何利用此方法。其實就是利用區段的概念,每個block都可以傳遞參數與程式碼,在最外層的程式碼去呼叫each方法的時候,會將區段內的程式碼往內(上)層傳,最後實際做的程式碼則是最內層的each。然而要如何接收其他區段內的程式碼呢,其實就是利用yields。如果對ruby區段有了解的人應該就知道跟怎麼做了,不過因為小弟資值駑鈍,無法參透所以還是看了其他大大的範例才會。實作方法很簡單,首先引入Enumerable 像是
class MyClass
include Enumerable
...
然後去定義個方法
def each
@elements.each {|elemant| yield element}
end
在這個範例中,是用另一個集合的each去實做此類別的each。如果有其他應用的話,一樣就是利用yield把程式碼傳進來,然後再把參數丟進去就OK了。

Comparable
這是本章的重點之二,利用此模組可以實做某類別的比較運算子(<, >, ==, <=, >=)。只要提供一個方法<=>,那麼接下來去就可以去比較拉~~。這個模組的實踐比較簡單,回傳0表式等於,回傳+1表是大於,-1則是小於。至於怎麼定義,就要看實作的內容了。
比較有趣的是,因為我曾經為了要讓Array時做此類別,於是自行定義了<=>。在小於與大於的表現上都合乎與我的預期,但是在==上我卻發現引入Comparable此模組並不會覆寫其類別原本所定義的==。雖然這是我想要的結果,不過卻是出乎我意料(我以為會被<=>方法所影響,因為Comparable實做了除了===的其他比較運算子),本來還在考慮要不要自己再去覆寫==,沒想到省了一道功夫。這也說明一件事,類別方法被覆寫的優先順序應該是模組方法,類別方法,自訂類別方法(已經有的類別方法,又去再覆寫他),越後面的使越不容易蓋掉。至於更大範圍的測是我還沒玩過,有機會再說吧。

alias
這是今天最後的重點了,用個很快樂的東西做個ending吧。當我們在快樂的複寫方法的時候,而又想要使用原來的方法要怎麼辦呢?剛開始讓人想到的應該就是super吧,這個super很快樂沒錯,不過當我們不是繼承某類別,從其子類別要去覆寫父親類別方法,而是想要複寫某個已存在類別的方法。如果我們就這樣傻傻給牠覆寫下去,裡面又使用到相同名稱的方法...那結果就會出現很精彩的遞迴又遞迴的遞迴地獄。所以~~!這時候就是alias出場的時候了。利用alias把原本的方法名稱指定成其他名子,這樣就可以安心的在覆寫的方法中使用原本的方法。
如果我沒是皮癢想要複寫Fixnum中的+變成兩次,可以這樣做
class Fixnum
alias plus +
def +(num)
self.plus(num).plus(num)
end
end
print "1 + 2 = ", 1+2
結果就會很開心了XXXD
當然alias不只可以用在這種地方,不過通常方法沒有被覆寫的的時候,應該不需要再給他一個名子吧。

沒有留言: