顯示具有 foreach 實作 標籤的文章。 顯示所有文章
顯示具有 foreach 實作 標籤的文章。 顯示所有文章

2008年7月14日 星期一

VB2005豆知識第一彈


很久沒有來發一些文章了....沒事還是要來補充一些料才好~^^。所以這次的內容就決定是來小談一下一些VB2005比較少人會談到的東西。基本上每個豆知識因為本身就是豆知識,所以當然內容也不會很多,究竟一次該弄多少料出來呢....我也不知道!而老實說呢...料也不多啦~~等改天有需要的時候自然會去研究然後就自己跑出來了~。

首先呢,先來補一下之前說要玩VB foreach的東西,其實我記得大約是寫完那邊JAVA的後一到兩天就玩完了,不過沒啥機會能夠順到PO就一直放在那了XXD。如果要能讓某個類別能夠支援foreach,就必須先實做IEnumerable界面,另外這個介面還需要一個Enumerator,所以必須還要再有一個類別是實做IEnumerator。說穿了,其實就是用一個Enumerator去逐一把整個陣列(或是串列)中的值一個一個丟出去,所以IEnumerable借面就是負責去丟Enumerator給外面呼叫foreach的地方。所以這邊也可很清楚的看到,使用foreach是絕對不適合用來改變Enumerable類別內的值。【範例檔下載】

一開始講就講foreach可能會讓人霧撒撒,沒關係,接下來講點比較簡單的!來談談要如何在VB 2005裡使用外部參數。這邊的外部參數的定義就是像是一般我們在執行程式的時候,有時候為了做一些特別的需要會把參數打在後面,就是檢查網路有時候會用到 ipconfig /all 後面的/all,或是檢查磁碟機時下的指令chkdsk c: /r 後面的c: /r。在C或是JAVA中,我們可以很簡單的重main後面去抓args,那VB2005呢?
其實很簡單,他就在My.Application.CommandLineArgs,要去使用他的話可以用foreach去把裡面的值全部讀出來,然後去做你要的處理就可以了。至於範例就免了吧,太簡單到沒辦法寫了...

那就來期待下期會出現什麼吧!!
如何使用drag and drop
如何使用剪貼簿
如何減少ListBox增加大量資料的時間
如何使用DataGidView表現出類似StringGrid的感覺

嗯....接下來就要等我看還有沒有想到什麼了...

2008年5月9日 星期五

For Each 面面觀與實作

今天要來討論的是...很快樂的for each!!目前眾多OO程式語言都有支援這類的語法,在不需要index的時候用起來還蠻方便的。我們知道說,像是在眾多的implements collection的類別中,都可以使用此語法,不過在一些我們所設計之特殊的資料結構(ADT, class)上,往往可能需要此類語法的支援,那麼怎樣才能夠針對我們所撰寫的資料結構,讓for each也能夠跑呢?

像是Ruby在前幾篇文章就有提到說,要如何實作其for each語法。在Ruby中是使用了Block的觀念去把上層的程式碼交給下層來處理,也就是說只要能提供類似 .each方法,逐一將直送進yield中即可達成我們要的目標。所以今天我們就來討論一下在JAVA要怎樣來實作。

首先我們先觀察一下目前有哪些類別可以被for each實作...google很快就跟我們說,像是List、Set、HashSet等等,繼承這些介面的類別都可以。透過查看Java doc我們可以很簡單的查覺,這些介面都是繼承於一個名叫做Iterable的介面,點進去看一下,嗯...很好,很清楚著寫著說,只要實作此介面者,都可以被for each所使用,只要在類別中把方法Iterator iterator()實作即可。於是,我們可以在繼續往下觀察Iterator...不過這邊就不再寫下去(學會看Java doc畢竟是基本工不是嗎?再說下去就會汙辱到看官的智商了)。

整理一下目前的情報,如果要能實作for each就必須實作自Iterable;而要實作Iterable,就必須要提供一個iterator。而一個iterator就需要實作三個方法boolean hasNext()、E next()、void remove()。其中remove則不一定要寫程式碼在裡面,看需求而定。而這邊就提供一個簡單而沒啥意義的簡單範例。


因為這個blog本身不適合張貼程式碼(空白會被吃掉),所以就將就一下,對照著看唄。在這個程式碼中,Node是最基礎的元件(類別),一方面是為了將抽象化的層次提高,另一方面則是Iterable本身需要參考的類別(ADT),而不能是基礎資料型態。而Nodes當然就是我們所需要的可以被foreach之類別,裡面提供了加入和刪除。最後是實作Iterator的Itr,基本上將Iterator放在Iterable的子類別是個不錯的選擇,可以很容易自在的取得上層類別的方法與物件。不過這次我是將整個Iterator寫的比較鬆,以利往後也許還有機會可以直接抓過來用,僅僅在remove用到了上層類別的delete,如果不要remove,獨立出來也是可以。

所以其實整個實作的重點就在於要丟出一個Iterator,其可以提供判斷還有沒有下一個元素(hasNext),亦要提供一個方法可以依序丟出集合中的元素(next)。Iterator 怎麼實作就是隨意了,不過基本上還是跟實作Iterable的類別脫離不了關係。這麼辛苦做出來的東西...實用性有多大是不知道(範例是沒啥用的XD),不過如果善加利用也許能夠增加整個程式的效率。

而如果覺得寫那麼多,卻沒啥fu,那還不如直接去繼承ArrayList等類別,善加利用類別中已經提供的方法,還是可以達到製作容器的目的,而且人家早就把程式碼寫好,可以專心處理類別中的其他部分,照樣還是可以用foreach。
(下次來挑戰看看VB好了XD)

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不只可以用在這種地方,不過通常方法沒有被覆寫的的時候,應該不需要再給他一個名子吧。