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//调用

 

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐