在某些英語口音中,當你快速說出「two for」時,聽起來就像「two fer」。 「Two-for-one」的意思是,如果你買一個,就可以免費得到一個。 所以「two-fer」這個詞通常暗示著買一送一的優惠。
想像一家麵包店有個節日優惠,你可以用一塊餅乾的價格買到兩塊餅乾(「two-fer one!」)。 你接受了這個優惠,並且(非常慷慨地)決定把多出來的那塊餅乾給隊伍中的另一個人喔。
你的任務是決定當你分送多出來的那塊餅乾時,要說什麼。
如果你知道對方的名字(例如對方叫 Do-yun),你會說:
One for Do-yun, one for me.
如果你不知道對方的名字,就改說 you。
One for you, one for me.
以下是一些例子:
| 名字 | 對話 |
|---|---|
| Alice | One for Alice, one for me. |
| Bohdan | One for Bohdan, one for me. |
| One for you, one for me. | |
| Zaphod | One for Zaphod, one for me. |
Odin 支援預設引數。 預設引數是一項實用的功能,讓你在需要相關但不同 API 的情境下,可以用不同的參數組合來呼叫程序。
少了預設引數,你的 API 最後可能會需要數量爆炸的程序。不支援預設引數的程式語言(例如 Java)得靠方法多載來達到同樣的效果(程式碼也更多),不然就得提供帶有一大堆引數的程序。
讓我們以greeting程序為例,假設我們希望能指定語言、指定名稱是否要轉成大寫,以及問候語結尾是否要加上驚嘆號。經過分析後,我們發現最大一群使用者會指定英文、不把名稱轉成大寫,也不想要結尾有驚嘆號;第二大的族群則會在問候語結尾加上驚嘆號。
我們可以寫出一個包含所有引數的單一程序:
greeting :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {
...
}
但這麼做會強迫所有使用者讀完每個引數的說明文件,而且每次都得把它們填滿。
沒有預設引數時,我們也可以定義多個帶有不同參數組合的程序:
greeting_common :: proc(name: string) {...}
greeting_with_exclamation :: proc(name: string) {...}
greeting_general :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {...}
// Odin supports overloading but it has to be explicitly defined
greeting :: proc {
greeting_common,
greeting_with_exclamation,
greeting_general,
}
如果你的程式語言像 Odin 一樣支援預設引數,就可以直接為最少用到的引數提供合理的預設值。呼叫者可以略過預設引數,讓程序採用提供的預設值,也可以覆寫它們。
greeting :: proc(name: string, language: Language = Language.English, do_uppercase : bool = false, add_exclamation: bool = false) {...}
// Note: because Odin supports type inference, we can simplify the interface.
greeting :: proc(name: string, language:= Language.English, do_uppercase := false, add_exclamation:= false) {...}
這個程序可以完全只用預設引數來呼叫:
greeting("John Doe")
對呼叫者重要的引數則可以覆寫:
greeting("John Doe", Language.Spanish)
如果你需要的引數正好照位置順序排列,就像上面的例子那樣,就不需要像上面那樣把引數名稱寫出來;但如果你需要略過其中幾個,就必須為你略過的第一個之後的引數命名。
greeting("John Doe", add_exclamation=true)
在這個練習中,你會實作一個程序,這個程序負責配置它回傳的字串。釋放這個字串則是程序呼叫者的責任。
// The procedure will be called like that:
str := two_fer("Alice")
// ...
// and eventually the caller will delete the string
delete(str)