如何分辨method 和 function 以及 argument 和 parameter 的差異

如何分辨method 和 function 以及 argument 和 parameter 的差異

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;
}

書中還有許多不錯的比較跟觀念,可以去找來翻看看。