最近在Kotlin代码中,我经常看到这样的写法:
interface Person {
fun saySomething()
}
class Adult: Person {
var name = ""
override fun saySomething() {
println("Hello world!")
}
fun weirdSay(block: Person.() -> Unit) {
println("包装一下")
this.block()
}
private fun sayMore() {
println("私有方法")
}
fun answer(question: String) {
println("$question 的答案")
}
}
fun main() {
val adult = Adult()
adult.weirdSay {
saySomething()
// sayMore() 无法找到私有方法
// answer("问题") 无法找到
}
}
输出为
包装一下
Hello world!
注意看main函数,这里调用了adult的weirdSay,传入一个lambda表达式,传入的居然是adult自己的saySomething,那是因为block: Person.() -> Unit语法
() -> Unit是Kotlin定义不接收任何参数并且不返回任何东西的函数的方式。
并且有一种方法可以指定该函数将在何处被调用,因此有了Person.()部分。
一个参数类型为 Person.() -> Unit 的 Lambda 表达式,它可以访问和修改 Person 类型的属性和方法,具体含义是:为“给我一个在Person上调用的块。它必须不接收任何参数,并且不返回任何东西。”
显然,这是一种定义即时扩展函数的方式。这允许你定义在类内部运行但是从类外部定义的函数。
也就是说,当我们需要在业务中用到某个类内部的方法时,我们可以给这个类内部增加一个类似于 fun weirdSay(block: Person.() -> Unit) {的方法,对需要调用的方法进行相应的处理,然后在外面直接调用weirdSay就行了,同时,在外部也可以访问或者修改属性
class Person(var name: String) {
fun say() {
println("My name is $name")
}
fun weirdSay(block: Person.() -> Unit) {
println("包装一下")
block()
}
}
fun main() {
val person = Person("Tom")
person.weirdSay {
name = "Jerry"
say()
}
}
输出为
包装一下
My name is Jerry
这样子,多数情况下,就可以在这一扩展函数中自由的像在person类中调用自己一样,比如
interface Person {
fun saySomething()
fun sayMore()
}
class Adult: Person {
override fun saySomething() {
println("Hello world!")
}
fun weirdSay(block: Person.() -> Unit) {
println("包装一下")
this.block()
}
override fun sayMore() {
println("sayMore")
}
}
fun main() {
val adult = Adult()
adult.weirdSay {
saySomething()
sayMore()
}
}
增加一个sayMore方法,也可以继续调用,weirdSay{}内部就像person的内部一样(除了private不能访问)
学习到了小技巧,就赶紧用到项目中吧!