天天看点

Kotlin(五)、函数定义与调用

一、为了更方便调用

一个函数定义如下:

/**
     * 实现输入一个集合,如1,2,3 通过这个方法打印出 (1;2;3)
     */
    fun <T> joinToString(collection: Collection<T>,//输入集合
                         separator: String,//分隔符
                         prefix: String,//前缀
                         postfix: String//后缀
    ): String {
        val result = StringBuilder(prefix)
        for ((index, element) in collection.withIndex()) {
            if (index > 0) result.append(separator)
            result.append(element)
        }
        result.append(postfix)
        return result.toString()
    }
           

调用:

joinToString(collection, ";", "(", ")")

命名参数

可以发现调用时可读性非常的差,如果不去查源码函数声明很难确定每个参数的含义,对于很多个Boolean类型的参数的函数更为明显。

未解决这一问题,Kotlin可以显式的标明参数名称

joinToString(collection, separator = ";", prefix = "(", postfix = ")")

注意:

  • 重命名函数的参数时要使用Rename处理,不能手动修改。
  • 调用Java函数时不能采用命名参数的方式
默认参数值

Java中一个普遍存在的问题是,一些类的重载方法是在是太多了。为了兼容性,导致重复。

在Kotlin中可以在声明函数时指定参数的默认值,这样可以避免一部分的重复。

改进一下之前的函数

fun <T> joinToString(collection: Collection<T>,//输入集合
                         separator: String = ";",//分隔符
                         prefix: String = "(",//前缀
                         postfix: String = ")"//后缀
    ): String
           

调用结果

joinToString(collection, ";", "(", ")")
 joinToString(collection, ";", "(")
 joinToString(collection, ";")
 joinToString(collection)
 //上面几种方式结果相同
           
消除顶层

如Java中的Util类,其中有静态变量和静态方法,使用类名点调用。

Kotlin中不需要在文件中创建了类,直接写方法或静态变量即可

二、扩展函数和属性

Kotlin可以为任何类添加成员函数

fun String.qit(): String return "1"
           

为String这个类添加了qit()函数,之后任何String类型的变量都会拥有这个函数

导入扩展函数

对于一个定义的扩展函数,他并不会自动的在整个项目中生效。为了避免偶然性的命名冲突,和其他函数一样,使用它需要进行导入。

import 包名.qit

//也可用*
import 包名.*

//还可以使用as来修改名称
import 包名.qit as tian
val c = "x".tian()
           

关键字as是解决命名冲突的唯一方式

注意:

  • 扩展函数相当于静态函数,不能被重写
扩展属性
//声明一个扩展属性
val String.mVal: String
    get() = "2"

//声明一个可变的扩展属性
var StringBuilder.mVar: String
    get() = "2"
    set(value) {
        this.setCharAt(1, '1')
    }
           

三、处理集合:可变参数、中缀调用和库的支持

可变参数
val list = listOf(1, 2, 3)
//可以发现创建List时可以传任意数量的参数进去
//函数在库中的声明如下
fun <T> listOf(vararg value: T): List<T> {
	...
}
           

vararg修饰符如同Java中三个点,不同的是当传入的参数包装在数组中时,Java可以直接传入数组,而Kotlin要求解包装,只需在数组前加

*

即可

fun main(args:Array<String>){
    val list = listOf("string1",*args)
}
           
中缀调用
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
           

这行代码中的

to

是一种特殊函数调用,叫中缀调用,放在目标对象名称和参数之间。中缀调用可以与只有一个参数的函数一起使用,无论是普通函数还是扩展函数。要允许使用中缀符号调用函数,需要使用infix修饰符标记。

下面是一个简版的to函数声明:

infix fun Any.to(other: Any) = Pair(this, other)//忽略泛型
           

使用

to

可以生成

Pair对象

val (number, name) = 1 to "one"//解构声明
           

四、局部函数和扩展

为减少重复代码,Kotlin可以再函数中声明嵌套的函数

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    if (user.name.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty Name")
    if (user.name.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty Address")

}
           

这段代码中重复代码很少,但如果字段很多而且全面的验证每一个字段的特殊情况,那就很麻烦了,使用局部函数之后可以这样:

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    fun validate(user: User, value: String, fieldName: String) {
        if (value.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
    }
    validate(user,user.name,"Name")
    validate(user,user.address,"Address")
}
           

因为局部函数可以访问函数中所有变量,所以可以去掉局部的User参数

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
    }
    validate(user.name, "Name")
    validate(user.address, "Address")
}
           

提取成为User的扩展函数

class User(val id: Int, val name: String, val address: String)

fun User.validateBeforeSave() {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) throw IllegalArgumentException("Can't save user $id: empty $fieldName")
    }
    validate(name, "Name")
    validate(address, "Address")
}

fun saveUser(user: User) {
    user.validateBeforeSave()
}