Kotlin入門(Android開發)基礎知識彙總(三)之函數運用

1.函數的基本用法

//java
@Override
public void onCreate(Bundle savedInstanceState) {
...
}

//Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
...
}

<1>使用小寫“override”在同一行表達重載操作;

<2>默認函數是公開的,忽略關鍵字“public”;

<3>不存在關鍵字void,若無返回參數,則不用特別說明;

<4>用關鍵字“fun”表示這裏是函數定義;

<5>使用“變量名稱:變量類型”聲明輸入參數的格式;

<6>如果某個變量爲空,需要在變量類型後面加個問號“?”。

1.1輸入參數的格式

函數既可以沒有輸入參數,也可以沒有輸出參數;或者只有輸入參數;輸入參數可空

//沒有輸入參數,沒有輸出參數
fun getDinnerEmpty() {
    tv_result.text = ""
}

//只有輸入參數
fun getDinnerInput(egg:Int, leek:Double, water:String, shell:Float) {
    tv_result.text = ""
}

//輸入參數存在空值
fun getDinnerCanNull(egg:Int, leek:Double, water:String?, shell:Float)
{
    tv_result.text = ""
}

1.2 輸出參數的格式

fun main():Int//輸入參數後加“:數據類型”

   開發者不聲明任何返回參數時,Kotlin默認返回一個Unit類型的對象。

fun getDinnerUnit():Unit {
    tv_result.text = ""
}
//只有輸出參數
fun getDinnerOutput():String {
    var dinner:String = "巧婦難爲無米之炊"
    return dinner
}
//同時具備輸入參數和輸出參數
fun getDinnerFull(egg:Int, leek:Double, water:String?, shell:Float):String { 
    var dinner = "橫看成嶺側成峯..."
    return dinner
}

1.3輸入參數的變化

默認參數

fun getFourBigDefault(general:String, first:String="造紙", second:String="印刷術",                         
third:String="火藥", fourth:String="指南針"):String {
    var answer:String = "$general:$first:$second:$third:$fourth"
    return answer
}

//如果調用參數沒有給出某參數的具體值,系統就自動對該參數賦予默認值
btn_input_default.setOnClickListener {
    tv_four_answer.text= getFourBigDefault("中國古代四大發明") 
}

命名參數

btn_input_part.setOnClickListener { 
    tv_four_answer.text=getFourBigDefault("中國古代四大發明","蔡倫發明的造紙") }

//如果不需要某參數默認值,只需調用“變量名="***"”
btn_input_name.setOnClickListener {
 tv_four_answer.text=getFourBigDefault("中國古代四大發明",second="活字印刷") }

可變參數

在Java體系中採取“Object... args”,Kotlin中使用關鍵字vararg,表示其後的參數個數是不確定的,以可變字符串爲例,則表示爲“vararg args: String?”。

fun getFourBigVararg(general:String, first:String="造紙術", second:String="印刷術", third:String="火藥", fourth:String="指南針", vararg otherArray: String?):String {
    var answer:String = "$general:$first:$second:$third:$fourth"
    //循環取出可變參數包含的所有字段
    for (item in otherArray) {
        answer = "$answer􀒅$item"
    }
    return answer
}
btn_param_vararg.setOnClickListener {
    tv_four_answer.text = if (isOdd) getFourBigVararg("古代四大發明") else         getFourBigVararg("古代的七大發明","造紙術","印刷術","火藥","指南針","絲綢","瓷器","茶葉")
    isOdd = !isOdd
}

可變數組參數

fun getFourBigVararg(general:String, first:String="造紙術", second:String="印刷術", third:String="火藥", fourth:String="指南針", vararg otherArray: Array<String>):String {
    var answer:String = "$general:$first:$second:$third:$fourth"
    //先遍歷每個數組
    for (array in otherArray) {
    //再遍歷數組元素
        for (item in array) {
            answer = "$answer:$item"
        }
    }
}
btn_param_array.setOnClickListener {
    tv_four_answer.text = if (isOdd) getFourBigArray("古代的四大發明") else getFourBigArray("古代的N大發明","造紙術","印刷術","火藥","指南針",arrayOf("絲綢","瓷器","茶葉"),arrayOf("國畫","中醫","武術"))
    isOdd = !isOdd
}

2.特殊函數

2.1泛型函數

定義泛型函數時,得在函數名稱前添加“<T>”,表示以T聲明的參數(包括輸入參數和輸出參數),其參數類型必須在參數調用時指定。

fun <T> appendString(tag:String, vararg otherInfo: T?):String {
...}
var count = 0
btn_vararg_generic.setOnClickListener {
    tv_function_result.text = when (count%3) {
    0 -> appendString<String>("古代的四大發明","造紙術","印刷術","火藥","指南針")
    1 -> appendString<Int>("小於10的素數",2,3,5,7)
    else -> appendString<Double>("燒錢的日子",5.20,6.18,11.11,12.12)
}
count++

2.2內聯函數

如果參數類型都是繼承自某種類型,那麼允許在定義函數時指定從這個基類泛化開,凡是繼承自該基類的子類,都可以作爲輸入參數進行函數調用,反之無法調用函數。舉個例子,Int、Float和Double都繼承自Number類,但是假如定義一個輸入參數形式爲setArrayNumber(array:Array<Number>)的函數,它並不接受Array<Int>或者Array<Double>的入參。如果要讓該方法同時接收整型和雙精度的數組入參,就得指定泛型變量T來自於基類Number,即將“<T>”或者“<reified T : Number>”,同時在fun前面添加關鍵字inline,表示該函數屬於內聯函數。

//該函數既不接收Array<Int>,也不接收Array<Double>
fun setArrayNumber(array:Array<Number>) {
    var str:String = "數組元素依次排列:"
    for (item in array) {
        str = str + item.toString() + ", "
    }
    tv_function_result.text = str
}
//只有內聯函數纔可以被具體化
inline fun <reified T : Number> setArrayStr(array:Array<T>) {
    var str:String = "數組元素依次排列:"
    for (item in array) {
        str = str + item.toString() + ", "
    }
    tv_function_result.text = str
}
var int_array:Array<Int> = arrayOf(1, 2, 3)
var float_array:Array<Float> = arrayOf(1.0f, 2.0f, 3.0f)
var double_array:Array<Double> = arrayOf(11.11, 22.22, 33.33)
btn_generic_number.setOnClickListener {
    when (count%3) {
        0 -> setArrayStr<Int>(int_array)
        1 -> setArrayStr<Float>(float_array)
        else -> setArrayStr<Double>(double_array)
    }
    count++
}
//btn_generic_number.setOnClickListener { setArrayNumber(int_array) }//報錯

2.3簡化函數

如果一個函數的表達式比較簡單,一兩行代碼就可以搞定,那麼使用等號代替大括號。示例:

fun factorial(n:Int):Int {
    if (n <= 1) n
    else n*factorial(n-1)
}

//簡化函數
fun factorial(n:Int):Int = if (n <= 1) n else n*factorial(n-1)

2.4尾遞歸函數

函數末尾的返回值重複調用了自身函數,該函數叫尾遞歸函數。此時要在fun前加上關鍵字tailrec,

//尾遞歸函數會使編譯器自動優化遞歸,即用循環方式代替遞歸,從而避免棧溢出的情況
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

2.5 高階函數

A函數作爲B函數的輸入參數,那麼B函數稱爲高階函數。

//greater方法作爲參數傳入,且其含有2個輸入參數,返回值爲布爾值
//如果第1個參數大於第2個參數,就認爲greater返回true,否則返回false
fun <T> maxCustom(array: Array<T>, greater: (T, T) -> Boolean): T? {
    var max: T? = null
    for (item in array)
        if (max == null || greater(item, max))
        max = item
    return max
}
var string_array:Array<String> = arrayOf("How", "do", "you", "do", "I'm", "Fine")
btn_function_higher.setOnClickListener {
    tv_function_result.text = when (count%4) {
        0 -> "字符串數組默認最大值爲${string_array.max()}"
        1 -> "字符串數組按長度比較的最大值爲${maxCustom<String>
(string_array, { a, b -> a.length > b.length })}"
        2-> " 字符串數組的默認最大值爲${maxCustom(string_array, { a, b -> a > b })}"
        else -> "字符串數組去掉空格再比較長度的最大值爲${maxCustom (string_array, { a, b -
> a.trim().length > b.trim().length })}"
    }
    count++;  
}

“{ a, b -> a.length > b.length }”這是Lambda表達式的匿名函數寫法,前半部分表示函數的輸入參數,後半部分表示函數體。按照規範的函數寫法是這樣:

fun anonymous(a:String, b:String):Boolean {
    var result:Boolean = a.length > b.length
    return result
}

3.增強系統函數

3.1擴展函數

允許開發者給系統類補寫新的方法,而無須另外編寫額外的工具類。

比如系統的Array類除了sort,max等方法,我們可以給它添加一個擴展函數swap

fun Array<Int>.swap(pos1: Int, pos2: Int) {
    val tmp = this[pos1] //this表示數組自身
    this[pos1] = this[pos2]
    this[pos2] = tmp
}
//擴展函數結合泛型函數能更好地擴展函數的功能
fun <T> Array<T>.swap(pos1: T, pos2: T) {
    val tmp = this[pos1] 
    this[pos1] = this[pos2]
    this[pos2] = tmp
}
val array:Array<Double> = arrayOf(1.0, 2.0, 3.0, 4.0, 5.0)
btn_function_extend.setOnClickListener {
    array.swap(0, 3)
}

3.2 擴展高階函數

給2.5提到的高階函數maxCustom添加擴展函數功能。該函數的目的是求數組元素的最大值,因此不妨加到Array<T>數組中去

fun <T> Array<T>.maxCustomize(greater: (T, T) -> Boolean): T? {
    var max: T? = null
    for (item in this)
        if (max == null || greater(item, max))
            max = item
    return max
}

string_array.maxCustomize({ a, b -> a.length > b.length })//調用

3.3 日期時間函數

Kotlin無須書寫專門的DateUtil工具類,直接改寫Date類的擴展函數即可,下面是幾個Date的擴展函數函數

//返回的日期時間格式形如 2017-10-01 10:00:00
fun Date.getNowDateTime(): String {
    val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    return sdf.format(this)
}

//只返回日期字符串
fun Date.getNowDate(): String {
    val sdf = SimpleDateFormat("yyyy-MM-dd")
    return sdf.format(this)
}

//只返回時間字符串
fun Date.getNowTime(): String {
    val sdf = SimpleDateFormat("HH:mm:ss")
    return sdf.format(this)
}

//返回詳細的時間字符串,具體到毫秒
fun Date.getNowTimeDetail(): String {
    val sdf = SimpleDateFormat("HH:mm:ss.SSS")
    return sdf.format(this)
}

//返回開發者指定格式的日期時間字符串
fun Date.getFormatTime(format: String=""): String {
    var ft: String = format
    val sdf = if (!ft.isEmpty()) SimpleDateFormat(ft)
        else SimpleDateFormat("yyyyMMddHHmmss")
    return sdf.format(this)
}


Date().getNowDate()//調用例子

3.4 單例對象

Kotlin使用對象關鍵字“Object”加以修飾,並稱之爲單例對象,相當於Java的工具類。

下面是採取單例對象改寫的日期時間工具代碼:

object DateUtil {

    //聲明一個日期時間的屬性
    //返回的日期時間格式形如2017-10-01 10:00:00
    val nowDateTime: String
        get() {
            //外部訪問DateUtil.nowDateTime時,會自動調用nowDateTime附屬的get方法得到它的值
            val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            return sdf.format(Date())
        }

    val nowDate: String
        get() {
            val sdf = SimpleDateFormat("yyyy-MM-dd")
            return sdf.format(Date())
        }
    ...
}

DateUtil.nowDateTime//調用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章