Kotlin - local function


  想必大家都赞同的一点是好代码都具有复用率高的特点。在初学编程的时候,你的老师也一定告诫过你:“不要让自己写重复的代码。”但在Java中,有时候并不能很好的践行这一原则。
  在大多数情况下,尽管你可以使用你的IDE帮你重构那些长得不得了的函数,让其分成更小的代码块,然后重用这些代码块。但这会让你的代码更加难以理解和阅读,这样做的最终结果会使你得到一个具有很多小方法的类,一旦使用这种做法的时间久了,你的这个类随着时间而渐渐累积了庞大数量的小方法,最终变得难以维护。
  这种情况下,Kotlin的local function的特性应运而生。
  看如下场景,你需要存储Person的数据,并且在存储之前判断数据是否合法:

class Person(val id: Int, val name: String, val profession: String)

fun savePerson(person: Person) {
    if (person.name.isEmpty()) {
        throw IllegalArgumentException(
                "Illegal: ${person.id} Name is empty!"
        )
    }
    if (person.profession.isEmpty()) {
        throw IllegalArgumentException(
                "Illegal: ${person.id} Profession is empty!"
        )
    }
}

fun main(args: Array<String>) {
    savePerson(Person(0,"",""))
}
//result:
Exception in thread "main" java.lang.IllegalArgumentException: Illegal: 0 Name is empty!
    at Kt04.Kt43Kt.savePerson(Kt43.kt:11)
    at Kt04.Kt43Kt.main(Kt43.kt:23)

Process finished with exit code 1

  这种写法就显得有点累赘了,看看怎么用local function来解决这个问题:

class Person(val id: Int, val name: String, val profession: String)
fun savePerson(person: Person) {
    //local function
    fun validate(person: Person,
                 value: String,
                 fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException(
                    "Illegal: ${person.id} $fieldName is empty!"
            )
        }
    }
    validate(person, person.name, "Name")
    validate(person, person.profession, "Profession")
}

fun main(args: Array<String>) {
    savePerson(Person(0,"",""))
}
//result:
Exception in thread "main" java.lang.IllegalArgumentException: Illegal: 0 Name is empty!
    at Kt04.Kt43Kt$savePerson$1.invoke(Kt43.kt:28)
    at Kt04.Kt43Kt.savePerson(Kt43.kt:33)
    at Kt04.Kt43Kt.main(Kt43.kt:38)

Process finished with exit code 1

  怎样?这样一来就简洁多了吧?判断数据是否合法的逻辑被很好的复用了。
  其实,local function是可以访问它所属的function的所有参数的。也就是说,还可以省略一些传入的参数:

fun savePerson(person: Person) {
    //不必再次声明参数person
    fun validate(value: String,
                 fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException(
                    "Illegal: ${person.id} $fieldName is empty!"//可以访问person
            )
        }
    }
    validate(person.name, "Name")
    validate(person.profession, "Profession")
}

  local function一样可以称为拓展方法,其声明和普通的拓展方法类似。