BOO入門/函數
內建函數
編輯前面幾個章節已經提過也使用過了部份函數:range()、print() 和 join()。這些都是 Boo 所內建的函數,這裏列出所有 Boo 提供的內建函數:
名稱 | 描述 | 範例 |
---|---|---|
將物件輸出到標準輸出。這與 System.Console.WriteLine 相同。 | print("hey") | |
gets | 從標準輸入取得字串,與 System.Console.ReadLine() 相同。 | input = gets() |
prompt | 詢問使用者特定問題並從標準輸入取得字串。 | input = prompt("How are you? ") |
join | 遍訪 IEnumerable 物件並將所有元素放到一個字串裏。 | join([1, 2, 3, 4, 5]) == "1 2 3 4 5" |
map | 對 IEnumerable 物件裏的全部元素執行同一函數,然後將結果放到一個新的 IEnumerable 物件之後回傳。 | for i in map([1, 2, 3, 4, 5], { x | return x*x } ): print i(譯註,例子與原文不同,這裏使用 closure (類似 C# 的 anonymous method),並加上迴圈印出結果。 ) |
array | 用來建立一個空陣列或是將 IEnumerable 和 ICollection 物件轉換為陣列。 | array(int, [1, 2, 3, 4, 5]) == (1, 2, 3, 4, 5) |
matrix | 建立多維陣列。請參考 Multidimensional Arrays 。(譯註:原文找不到此節。) | matrix(int, 2, 2) |
iterator | 從物件取得一個 IEnumerable | List(iterator('abcde')) == ['a', 'b', 'c', 'd', 'e'] |
shellp | 啟始一個程序,並回傳 Process 物件。 | process = shellp("MyProgram.exe", "") |
shell | 執行應用程式,並將應用程式輸出到標準輸出的結果放到字串裏面回傳。 | input = shell("MyProgram.exe", "") // 譯註:原文為 "echo hi there" ,經測試,不管是在 Windows 或 Linux 都無法執行 |
shellm | 在新的 AppDomain 裏執行特定 managed 應用程式,同樣,會把應用程式輸出到標準輸出的結果放到字串裏面回傳。 | input = shellm("MyProgram.exe", (,)) |
enumerate | 從 IEnumerator 物件建立新的 IEnumerator,但是會變成類似 (index, value) 的形式。 | array( enumerate( range(5,8) ) ) == ((0, 5), (1, 6), (2, 7)) (譯註:原文用 List,這裏改用 array,因為用 List 會傳回 object,不容易看出結果。) |
range | 回傳包含整數串列的 IEnumerable 物件。 | List(range(5)) == [0, 1, 2, 3, 4] |
reversed | 回傳 IEnumerable,但裏面成員的順序會變成相反。 | List(reverse(range(5))) == [4, 3, 2, 1, 0] |
zip | 會回傳一個經過混搭多個 IEnumerables 物件的 IEnumerable 物件。 | array(zip([1, 2, 3], [4, 5, 6])) == ((1, 4), (2, 5), (3, 6)) (譯註:原文為 List([1,2,3],[4,5,6]),應為 zip 才對,此處已修正) 或看這個例子:array(zip(['a','b','c'],[4,5,6],['aa','bb','cc']))==(('a', 4, 'aa'), ('b', 5, 'bb'), ('c', 6, 'cc')) |
cat | 串接多個 IEnumerable 物件。 | List(cat(range(3), range(3, 6)) == [0, 1, 2, 3, 4, 5] |
這些函數你都應該要知道,因為他們非常有用,能讓寫程式變得更簡單。
定義自己的函數
編輯定義自己的函數非常簡單:
// 宣告函數
def Hello():
return "Hello, World!"
print Hello()
輸出結果
Hello, World!
如果你不懂的話,下面會一步步地解說:
- def Hello():
- def 表示你要開始宣告一個函數,def 表示 define。
- Hello 是函數的名稱。你可以取任何你想要的名字,但這名字裏不能有空白,也不能以數字開頭。
- () 表示函數要使用的引數。這裏不使用任何引數,所以裏面是空的。
- return "Hello, World!"
- return 是個關鍵字,這讓函數知道該回傳些什麼給呼叫這個函數的地方。
- "Hello, World!" 是個字串,也就是 return 要回傳的東西。
- print Hello()
- print ,我們之前提過了,就是印出變數的內容。
- Hello() 呼叫 Hello 函數,並且不帶引數。
如同變數一樣,函數回傳值的型別也會被自動推斷並決定。所以,
def Hello():
return "Hello, World!"
Hello() 將永遠回傳字串,所以 Boo 將會推斷字串是他的回傳型別。也就是跟下面的程式碼一樣:
def Hello() as string:
return "Hello, World!"
如果 Boo 無法推斷回傳型別,它會假設為 object。如果沒有回傳值,那麼回傳型別會是 void,void 表示不回傳值。要定義一個無回傳值的函數,就不要在函數裏面使用 return,或就寫 return 就好。如果函數裏面有好幾個 return,而回傳值的型別又不同的時候,回傳型別將會是最接近的原型,通常是 object,但並非絕對。
譯註:"回傳型別將會是最接近的原型"的意思是,如果回傳的值剛好都繼承同一個父類別時,回傳型別將會被推斷為它們的父類別。但因為 .Net 裏面所有型別都兼容於 object,所以才說,"通常是 object"。另外,說兼容的原因是,像 int、bool, decimal 等等其實都是 struct,並不繼承 object。
引數
編輯引數非常有用,這允許函數可以依據輸入來做出不同的事情。
// 引數範例
def Hello(name as string):
return "Hello, ${name}!"
print Hello("Monkey")
輸出結果
Hello, Monkey!
這裏同樣提供步驟的說明:
- def Hello(name as string):
- def 表示開始宣告函數。
- Hello 是函數的名稱。你可以用任何你可以想到的名字,但是不能有空白,也不能以數字開頭。
- (name as string) 這表示函數要使用的引數。這個函數將會使用一個引數:name。當呼叫此函數時,name 必須是個字串,否則你會得到一個編譯錯誤 - "The best overload for the method Hello is not compatible with the argument list '(The,Types, of, The, Parameters, Entered)'."
- return "Hello, ${name}!"
- return 是個關鍵字,表示離開函數,並且可以傳回一個值給呼叫者(當然也可以不傳回值)。
- "Hello, ${name}!" 使用了字串插值將 name 的值直接放到字串裏面去。
- print Hello("Monkey")
- print 正如之前提到的,就是將物件印出的 macro。
- Hello("Monkey") 將 ("Monkey") 當作引數傳入並呼叫 Hello 函數。
函數的多載
編輯當函數被以不同引數宣告了數次時,函數多載就發生了。
// overloading example
def Hello():
return "Hello, World!"
def Hello(name as string):
return "Hello, ${name}!"
def Hello(num as int):
return "Hello, Number ${num}!"
def Hello(name as string, other as string):
return "Hello, ${name} and ${other}!"
print Hello()
print Hello("Monkey")
print Hello(2)
print Hello("Cat", "Dog")
輸出結果
Hello, World! Hello, Monkey! Hello, Number 2! Hello, Cat and Dog!
不定個數的引數
編輯要傳遞不定數目的引數時,可以這麼作:
// 不定引數的範例
def Test(*args as (object)):
return args.Length
print Test("hey", "there")
print Test(1, 2, 3, 4, 5)
print Test("test")
a = (5, 8, 1)
print Test(*a)
輸出結果
2 5 1 3
在函數對引數的宣告加上 * 是讓函數知道引數的數目將不固定,如果要直接把容器變數當作引數傳遞時,得在呼叫函數時加上 *,以表示要把指定容器變數裏的元素當作引數傳遞到函數裏面去。以上面的例子來說,也就是把 a 裏面的三個元素當作引數傳遞到函數裏面去。 如果有一定需要(也就是必要)的引數的話,請宣告在不定引數的前面,可千萬別放到不定引數後面去了。
練習
編輯- 寫個函數,讓它能在傳入值為偶數時,印些好的字眼﹔在傳入值為奇數時,印些不好的字眼。