本人也是在初学Kotlin,如有错误,请帮忙指出,持续更新
Android:Kotlin详细入门学习指南-高阶函数-基础语法(七)
建议先看看前面的文章
Android:Kotlin详细入门学习指南-基础语法(一)
Android:Kotlin详细入门学习指南-基本类型-基础语法(二)
Android:Kotlin详细入门学习指南-包-控制流-返回与跳转-基础语法(三)
Android:Kotlin详细入门学习指南-类和对象-基础语法(四)
Android:Kotlin详细入门学习指南-类和对象(下)-基础语法(五)
Android:Kotlin详细入门学习指南-函数-基础语法(六)
这篇文章分享的内容比较多,建议先关注收藏,再查看,以免迷路
高阶函数
高阶函数就是可以接受函数作为参数并返回一个函数的函数
字面函数和函数表达式
字面函数或函数表达式就是一个 "匿名函数",也就是没有声明的函数,但立即作为 表达式传递下去。
max(strings, {a, b -> a.length < b.length })
max 函数就是一个高阶函数,它接受函数作为第二个参数。第二个参数是一个表达 式所以本生就是一个函数,即字面函数。作为一个函数,相当于:
fun compare(a: String, b: String) : Boolean = a.length < b.lengt h
函数类型
一个函数要接受另一个函数作为参数,我们得给它指定一个类型。
fun max(collection: Collection, less: (T, T) -> Boolean ): T? {
var max: T? = null
for (it in collection)
if (max == null || less(max!!, it))
max = it
return max
}
参数 less 是 (T, T) -> Boolean 类型,也就是接受俩个 T 类型参数返回一 个 Boolean :如果第一个参数小于第二个则返回真。 在函数体第四行, less 是用作函数
val compare: (x: T,y: T) -> Int = ...
函数文本语法
val sum = {x: Int,y: Int -> x + y}
函数文本总是在大括号里包裹着,在完全语法中参数声明是在括号内,类型注解是 可选的,函数体是在 -> 之后,像下面这样:
val sum: (Int, Int) -> Int = {x, y -> x+y }
函数文本有时只有一个参数。如果 kotlin 可以从它本生计算出签名,那么可以省略 这个唯一的参数,并会通过 it 隐式的声明它:
```kotlin
ints.filter {it > 0}//这是 (it: Int) -> Boolean 的字面意思
注意如果一个函数接受另一个函数做为最后一个参数,该函数文本参数可以在括号 内的参数列表外的传递。
函数表达式
上面没有讲到可以指定返回值的函数。在大多数情形中,这是不必要的,因为返回 值是可以自动推断的。然而,如果你需要自己指定,可以用函数表达式来做:
fun(x: Int, y: Int ): Int = x + y
闭包
一个字面函数或者表达式函数可以访问闭包,即访问自身范围外的声明的变量。不 像 java 那样在闭包中的变量可以被捕获修改:
var sum = 0 ins filter {it > 0} forEach {
sum += it
}
print(sum)
内联函数
inline 标记即影响函数本身也影响传递进来的 lambda 函数:所有的这些都将被 关联到调用点。 内联可能会引起生成代码增长,但我们可以合理的解决它(不要内联太大的函数)
inline fun lock(lock: Lock,body: ()-> T): T { //... }
为了你想要一些 lambda 表达式传递给内联函数时是内联的,你可以给你的一些函 数参数标记 @noinline 注解:
inline fun foo(inlined: () -> Uint, @noinline notInlined: () -> Unit) { //... }
内联的 lambda 只能在内联函数中调用,或者作为内联参数,但 @noinline 标记 的可以通过任何我们喜欢的方式操控:存储在字段,( passed around etc)
返回到非局部
在 kotlin 中,我们可以不加条件的使用 return 去退出一个命名函数或表达式函 数。这意味这退出一个 lambda 函数,我们不得不使用标签,而且空白的 return 在 lambda 函数中是禁止的,因为 lambda 函数不可以造一个闭合函数返回:
fun foo() {
ordinaryFunction {
return // 错误 不可以在这返回
}
}
但如果 lambda 函数是内联传递的,则返回也是可以内联的,因此允许下面这样:
fun foo() {
inlineFunction {
return //
]
}
注意有些内联函数可以调用传递进来的 lambda 函数,但不是在函数体,而是在另 一个执行的上下文中,比如局部对象或者一个嵌套函数。在这样的情形中,非局部 的控制流也不允许在lambda 函数中。
内联 lambda 不允许用 break 或 continue ,但在以后的版本可能会支持。
实例化参数类型
有时候我们需要访问传递过来的类型作为参数:
fun TreeNode.findParentOfType(clazz: Class): T? {
var p = parent
while (p != null && !clazz.isInstance(p)) {
p = p?.parent
}
@suppress("UNCHECKED_CAST")
return p as T
}
现在,我们创立了一颗树,并用反射检查它是否是某个特定类型。一切看起来很 好,但调用点就很繁琐了:
myTree.findParentOfType(javaClass() )
我们想要的仅仅是给这个函数传递一个类型,即像下面这样:
myTree.findParentOfType()
为了达到这个目的,内联函数支持具体化的类型参数,因此我们可以写成这样:
inline fun TreeNode.findParentOfType(): T? {
var p = parent
while (p != null && p !is T) {
p = p?.parent
}
return p as T
}
用 refied 修饰符检查类型参数,既然它可以在函数内部访问了,也就基本上接 近普通函数了。因为函数是内联的,所以不许要反射,像 !is `as`这样的操作 都可以使用。同时,我们也可以像上面那样调用它了
myTree.findParentOfType()
尽管在很多情况下会使用反射,我们仍然可以使用实例化的类型参数 javaClass() 来访问它:
inline fun methodsOf
fun main(s: Array
println(methodsOf
}
普通的函数(没有标记为内联的)不能有实例化参数。