Your Site Title

kotlin function

Infix notation

使用infix修饰的函数, 必须满足:

infix操作优先级低于算术运算符, 类型转换, rangTo操作

High-order functions and lambdas

高阶函数是以函数为参数或者返回值. 函数类型 (A, B) -> C 函数类型设置nullable, ((Int, Int) -> Int)? 函数类型可以联合 (Int) -> ((Int) -> Unit), 使用right-associative (Int) -> (Int) -> Unit == ((Int) -> (Int)) -> Unit

实例化一个函数类型:

A value of a function type can be invoked by using its invoke(…) operator: f.invoke(x) or just f(x)

Lambda expressions

function literals: Lambda expressions 和 anonymous functions

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

如果函数最后一个参数是函数, 那么可以使用Passing trailing lambdas lambda表达式如果只有一个参数, 参数可以省略, 并且有隐匿it表示这个参数 lambda表达式可以显示使用return返回, 也可以隐匿使用最后一个表达式返回 LINQ-style strings.filter { it.length == 5 }.sortedBy { it }.map { it.uppercase() } lambda表达式中不使用的参数, 可以使用_占位

Anonymous functions

lambda表达式不能指定返回值类型, 使用匿名函数可以指定返回值. non-local returns. lambda返回是上层函数, 匿名函数返回是本身

fun(x: Int, y: Int): Int = x + y

匿名函数参数和返回值类型如果可以上下文推断, 那么可以省略类型

ints.filter(fun(item) = item > 0)

Function literals with receiver

A.(B) -> C

kotlin提供函数字面值接收者类型, 可以使用接收者调用该函数.

class HTML {
    fun body() { ... }
}

fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()  // create the receiver object
    html.init()        // pass the receiver object to the lambda
    return html
}

html {       // lambda with receiver begins here
    body()   // calling a method on the receiver object
}

inline functions

高阶函数是一个对象, 并且捕获一个闭包. 内存分配和虚拟调用引入运行时开销. 大多上述情况可以使用内联lambda表达式解决

inline fun <T> lock(lock: Lock, body: () -> T): T { ... }

lock(l) { foo() }
// 会转成
l.lock()
try {
    foo()
} finally {
    l.unlock()
}

内联有可能增长代码, 但在性能上获得回报

如果不想所有的lambda都内联, 可以使用noinline, 如果内联函数没有包含函数参数, 就会警告. 使用@Suppress("NOTHING_TO_INLINE") breakcontinue 不能在内联函数中使用.

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }

内联函数支持reified type parameters

fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
    var p = parent
    while (p != null && !clazz.isInstance(p)) {
        p = p.parent
    }
    @Suppress("UNCHECKED_CAST")
    return p as T?
}
treeNode.findParentOfType(MyTreeNode::class.java) // 不好看

inline fun <reified T> TreeNode.findParentOfType(): T? {
    var p = parent
    while (p != null && p !is T) {
        p = p.parent
    }
    return p as T?
}
treeNode.findParentOfType<MyTreeNode>()

inline fun <reified T> membersOf() = T::class.members

Inline properties, 标注在accessors上就是getter或者setter内部, 标注在字段上就是getter和setter上都内联

如果内联函数是public或者property, 那么就是公共API内联函数. 如果内联函数修改, 但调用模块没有重新 编译, 会导致二进制不兼容

internal内联函数, 使用@PublishedApi修饰成公共API内联函数.

Operator overloading

使用operator关键字重写操作符, 如果是override函数, 那么operator可以省略

+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()

a++ a.inc() + see below
a-- a.dec() + see below

a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a..b a.rangeTo(b)

a in b b.contains(a)
a !in b !b.contains(a)

a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ..., i_n) a.invoke(i_1, ..., i_n)

a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b)

a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))

a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0

Reference