在 Android Development with Kotlin: Enhance your skills for Android development using Kotlin 這本書提到了幾個不錯的觀念,其中有幾個是區分 method 和 function 以及 argument 和 parameter 的差異,裡面也有很不錯的基礎觀念,趁機可以來弄懂一下,比如說 tail-recursive 跟 recursive 有什麼分別,在 Kotlin 裡面有什麼限制?
說明
method vs function
method 翻譯成方法,function 翻譯成函式,在這本書的描述的差異點如下。
A function is a piece of code that is called by name.
The method is a function associated with an instance of class (object).
所以我們可以看作在類別內的 functions,我們統一稱作 methods。
宣告在類別外的 functions 就是 function。
在 Java 是物件導向,所以裡面都是 method,但是如果是靜態 method 就可以稱作 fact functions。
在 Kotlin 是 functional programming,因此,我們都以 function 稱之。
argument vs parameter
An argument is an actual value that is passed to the function when a function is called.
Parameter refers to the variables declared inside function declaration.
簡單來說就是宣告成 function 的時候,傳入的參數就叫做 parameter ,反之,如果是要 call 一個 function 時,所傳入的實質參數,就叫做 argument。
這邊有給一個實際的例子。
fun add(a1: Int, a2: Int){
print(a1 + a2)
}
add(3, 5)
a1 和 a2 是 parameter。
3 跟 5 是 argument。
tail-recursive vs recursive
遞迴是一種簡單的概念,它透過不斷地呼叫自己,並且將當前計算的結果存在堆疊中,這會造成一個很大的問題就是當遞迴太深,會引發 StackoverflowError 的錯誤被拋出。
fun getState(state: State, n: Int): State =
if (n <= 0) state
else getState(nextState(state), n - 1)
這樣有一個經典的解決辦法,那就是用迴圈來取代遞迴。
fun getState(state: State, n: Int): State {
var s = state
for(i in 1..n){
s = state.nextState()
}
return s
}
這種解法被內建在 Kotlin 中,我們稱作 tail-recursive function,你可以把它看成一種進化版的遞迴,但是它有存在一些限制。
你可以這樣宣告它。
tailrec fun getState(state: State, n: Int): State =
if (n <= 0) state
else getState(nextState(state), n - 1)
如果你將其反組譯看看,會看到以下程式碼。
public static final State getState(@NotNull State state, int n){
while(true){
if(n <= 0){
return state;
}
state = state.nextState();
n = n - 1;
}
}
再來講一下它有哪些限制。
-
必須要在最後一行呼叫這個 function
-
function 內不能包含 try / catch / finally 區塊
-
回傳時,只能有一個 operator
最後一句代表著什麼?
這意思是說你只能回傳一次運算,也就是說,費氏數列是無法在這邊進行增強型遞迴的。
tailrec fun fibonacci(n: Int): Int {
if (n == 1 || n == 2) {
return 1
} else {
return fibonacci(n - 2) + fibonacci(n - 1)
}
}
我們試著反編譯看看,你會發現無法轉換。
public static final int fibonacci(int n) {
return n != 1 && n != 2?fibonacci(n - 2) + fibonacci(n - 1):1;
}
書中還有許多不錯的比較跟觀念,可以去找來翻看看。