這次的流水帳有地雷(簡單的劇情)。
Boo(8)-迴圈
基本上迴圈有兩種:for 與 while。
for 與一般語言的 for 不太一樣,反而與 foreach 比較類似,為了要能得到一個 Enumerator,通常都搭配 range():
// 印出 0 到 4 for i in range(5): print i
while 也沒什麼特別的:
// 同樣印出 0 到 4 i=0 while i<4: print i i=i+1
Boo Primer還有提出所謂的 do-while,但實際上是運用 while + break + unless修飾詞來達成的:
// 也是印出 0 到 4 i=0 while true: print i i=i+1 break unless i<4
有 break,當然也有 continue:
// 印出 1 3 5 7 9 for i in range(10): continue if i%2==0 print i
另外再提一個關鍵字,就是 pass,這用來表示程式區塊內不做事情:
// 不會輸出任何結果,因為被 pass 掉了... i=2 if i%2==0: pass else: print "i!=2"
Boo and Split
剛好遇到這種狀況,要依據字串的某字元然後做出陣列。所以很直覺地,就可以寫出這樣的代碼。
splitter = ( char(','), char('\n') )
fields = inputText.Split( splitter )
不過這段代碼足以讓人搞半天了,boo 會不讓你執行。
非常感謝Google 網上論壇 的Boo Programming Language群組:
正好解答了我的問題,原來要這樣寫:
splitter = ( char(','), char('\n') )
fields = inputText.Split( *splitter )
這真是太隱晦不明了…
Boo(7) – if-elif-else、unless
Boo 的 if 述句與 python 相似:
i=5 if i>5: print "i大於5" elif i==5: print "i等於5" else: print "i小於5"
很簡單。這邊額外要提到程式區塊的概念,像 C# 是用 { },Pascal 用 begin end,Python 與 Boo 是用縮排來決定程式區塊,所以縮排使用的字元很重要,千萬不要混雜使用,否則你會錯的莫名其妙,在開發時,最好一開始就決定好要使用 tab 字元或是特定數目的空白字元。
運算式,可以使用 and, or 來作連接,或是使用 not 來表示需要相反的條件式。
i=7 if i>=5 and i<=10: print "i 介於 5~10 之間" else: print "超出範圍" if not i==5: print "i不等於5"
如果你沒接觸過 perl/python/ruby/php 的話,以下的用法應該會讓你感到新奇:
s="sad" unless s=="sad": print "Hello world!" print "Hello world!" unless s=="sad" print "I am sad" if s=="sad"
unless 是反面的 if,把它想成 if not 就對了,所以第三行並不會被執行。
此外,unless 與 if 也可以用來修飾前面的述句﹔以第四行來說,unless s==”sad”用來修飾前面的 print “Hello world!”﹔以第五行來說,if s==”sad”用來修飾前面的print “I am sad”﹔當條件符合時,才會印出。
因此第四行的 “Hello world!” 不會被印出,而第五行的 “I am sad” 則會被印出。
這些用法會讓人覺得程式也很口語化~
TIOBE 2008/4的程式語言排行
今年(2008)四月的統計結果(TIOBE Programming Community Index for April 2008),C#只排到 8,Boo 排到 57。
有趣的是,Visual Basic 與 FoxPro/xBase 居然名次還往上衝了~Visual Basic 排到 3,FoxPro/xBase 排到 17。
電影流水帳(2008/04/25~2008/04/26)
兩天衝完四部片,夠猛!不過只有一部片我覺得比較好看~
- Step up(Wikipedia),中譯:舞出我人生。這應該算是青春勵志片,一個小混混因為跟朋友進馬里蘭學校搞破壞,結果被逮住,法庭判他去學校勞動服務。事情往往就是那麼剛好,女主角因為舞伴受傷,剛好又發現他有才華,於是就找他幫忙,就這樣,發生了一連串的故事。普通,今年好像要上 2 的樣子。
- Miss little sunshine(IMDB, Wikipedia),中譯:小太陽的願望。這部片子蠻好看的耶,帶小女兒去參加選美的旅行途中發生了一連串的事情,最後大家都解開心結,真的相當好看。
- Catch that kid(Wikipedia),中譯:小鬼神偷。深愛老爸的女主角,為了突然癱瘓的老爸鋌而走險,去偷銀行的錢,最後以喜劇收場。偷銀行,這算是拍給小朋友看的電影嗎?整體來說普普通通,女主角後來有演出Jumper(移動世界),擔任女主角年輕的時候,出現片段很短。
- Miami Vice(IMDB, Wikipedia),中譯:邁阿密風雲。雖說是從影集翻拍的,但老實說,我覺得翻拍的不怎麼樣,劇情普通。原本對這部片子很期待的說,因為演員陣容還蠻堅強的。
電影流水帳(2008/04/22~2008/04/24)
Boo(6)-變數
Boo 的變數宣告方法很簡單,就跟大多數的 script 語言一樣,指定即用。
比較特別的地方有三個:
- 在第一次指定以後,該變數型別就確定了,之後若指定其他型別的值給它,會發生錯誤。這邊的行為跟 Python、Ruby、Javascript等 script 語言不同,要特別注意。這也證明了 Boo 具有靜態語言的特性。
- 字串裡可以用 ${var_name} 的方式,會直接把 var_name 的值放到變數裡面去。
- 字串有三種定義方法:
- 雙引號,如”Hello”
- 單引號:跟雙引號的不同處,在於單引號字串不解釋 ${},所以 print ‘${var}’ 會印出 ${var},而不是 var 變數的值。
- 三個雙引號,如 “””Hello”””,跟前兩者的差別在於可以跨越多行。這跟 python 一樣。
// var.boo
i = 100
s = "Hello world ${i} times!!"
print s
// 如果把 100 指派給 s,就會發生錯誤
// s = 100
// Boo Primer 說可以像下面這樣寫,但經過我試驗,是不行的。
// s as int = 200
// 但這樣寫,卻是可以的
o as object = 300
print o
o = "I am object"
print o
print """Hello
Line1
Line2
Line3"""
Boo 官方建議不要特別花心思去寫 <variable> as <type> = <value> 這樣的語法,盡量使用 <variable> = <value>。
經過編譯(booc -target:exe var.boo)以後,再用 reflector 去反組譯,產出的C#代碼如下:
private static void Main(string[] argv)
{
int num = 100;
Console.WriteLine(new StringBuilder("Hello world ").Append(num).Append(" times!!").ToString());
object obj2 = 300;
Console.WriteLine(obj2);
obj2 = "I am object";
Console.WriteLine(obj2);
Console.WriteLine("Hello\r\nLine1\r\nLine2\r\nLine3");
}
從反組譯出來的結果看來,Boo都幫你自動處理好了,的確是不用特別花心思去寫。
電影流水帳(2008/04/17~2008/04/21)
一部是可能有續集的動作片,另一部算是劇情片。有時候在想,我是不是應該要跟一些專門介紹電影的網站一樣,寫的長篇大論呢?還是保持我言簡意賅的風格,簡單交代我的感想即可?
- Jumper(IMDB, Wikipedia),中譯:移動世界,中文片名我倒是覺得可以用時空跳躍者。這故事不錯,看了維基百科上的介紹,果然是由Steven Gould的小說改編,劇情介紹就不多說了,網路上還蠻多人推薦這部片子的,Google it!整部片子到最後,仍然是沒有解釋為什麼Paladin要追蹤並殺害Jumper,我想這應該會有第二集來作Paladin與Jumper的前因後果吧~
- The bucket list(IMDB, Wikipedia),中譯:一路玩到掛。雖然中譯片名與英文片名不符,但是我覺得意思有到了,片子的確就是告訴你,不要愁眉慘霧地等死,勇敢地把想做的事情列出來,然後努力去作,這不就是一路玩到掛?不過其實有很多事情並不是真的說要作就能做的,還是得像片裡的Jack Nicholson一樣那麼有錢才行啊~附帶一提,找這兩個老傢伙演員演,真的是找對人了。
Boo(5) – Console.ReadKey()
承接上篇的討論,經過 Hack 之後,發現原因就出在 Console.ReadKey()。
booish 與 IronPython 為了要能達到自己的需求,所以並不使用 Console.ReadLine(),而是使用 Console.ReadKey() 自行處理收到的按鍵並輸出。
為了要知道為甚麼會有問題,我試著寫了一個小程式,想知道相似的方式,是否也會有同樣的問題發生:
// Program: readkey.cs
// How to compile: gmcs /target:exe readkey.cs
using System;
public class Hello {
public static void Main( string[] args ) {
Console.TreatControlCAsInput = true;
ConsoleKeyInfo keyInfo;
do
{
keyInfo = Console.ReadKey( true );
Console.Write( keyInfo.KeyChar );
} while( keyInfo.Key!=ConsoleKey.Escape );
}
}
這個小程式編譯以後,使用 .NET 來執行,一切正常,但使用Mono Windows 版來執行,就硬是會 echo 出兩次。
經過用Reflector比對以後,發現Mono的 Console.ReadKey() 的迴圈條件式有問題。
如果將該條件式修正為:
// } while( record.EventType != 1 && !record.KeyDown); // original } while( !(record.EventType==1 && record.KeyDown ) ); // 附帶一提,這是 Windows .NET 的版本的變形,多判斷了 Character=='' 與 VirtualKeyCode 不是 Ctrl、alt、shift、numlock、caplock、scrolllock 的情況 //} while( !(record.EventType==1 && record.KeyDown ) || record.Character=='' && ( ((record.VirtualKeyCode0x12) && record.VirtualKeyCode!=0x14 && record.VirtualKeyCode!=0x90 ) ? (record.VirtualKeyCode==0x91) : true ) );
就可以解決問題,我想這可能是因為寫作 WindowsConsoleDriver.cs 的人對 ReadConsoleInput() 不夠清楚的緣故,不過其實我也是看了 source code 才知道要這樣去判斷。
總之,一切就此水落石出。
等等,可是為甚麼 Console.ReadLine() 沒有問題呢?嗯嗯,這邊的原因也很簡單,因為不管是 .NET 的 CLR 或是 Mono,都是調用 stdin 進行處理,所以就沒有這樣的問題了。
解決方法,目前並沒有,應急的方法是自行下載原始碼,修正Console.ReadKey()(在class/corlib/System/WindowsConsoleDriver.cs)以後,再編譯。不急的話,是先上Mono Buzilla去找找看是否有人回報過此問題,如果沒有再回報上去。
晚點要去找找看,然後回報上去,希望下個版本能解決。