但在大多数这种开销是可以通过内联文本函数避免。下面就是一个很好的例子。 函数可以很容易的在内联点调用。思考一下下面的例子:

    (Instead of creating a function object for the parameter and generating a call),编译器可以忽略下面的代码:

    1. lock.lock()
    2. try {
    3. foo()
    4. }
    5. finally {
    6. lock.lock()
    7. }

    这不正是我们最开始想要的吗?

    为了让编译器这样做,我们需要用 inline 标记 lock() 函数:

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

    inline 标记即影响函数本身也影响传递进来的 lambda 函数:所有的这些都将被关联到调用点。

    内联可能会引起生成代码增长,但我们可以合理的解决它(不要内联太大的函数)

    1. inline fun foo(inlined: () -> Uint, @noinline notInlined: () -> Unit) {
    2. //...

    内联的 lambda 只能在内联函数中调用,或者作为内联参数,但 标记的可以通过任何我们喜欢的方式操控:存储在字段,( passed around etc)

    注意如果内联函数没有内联的函数参数并且没有具体类型的参数,编译器会报警告,这样内联函数就没有什么优点的(如果你认为内联是必须的你可以忽略警告)

    在 kotlin 中,我们可以不加条件的使用 去退出一个命名函数或表达式函数。这意味这退出一个 lambda 函数,我们不得不使用标签,而且空白的 return 在 lambda 函数中是禁止的,因为 lambda 函数不可以造一个闭合函数返回:

    但如果 lambda 函数是内联传递的,则返回也是可以内联的,因此允许下面这样:

    1. fun foo() {
    2. inlineFunction {
    3. return //
    4. ]
    5. }

    注意有些内联函数可以调用传递进来的 lambda 函数,但不是在函数体,而是在另一个执行的上下文中,比如局部对象或者一个嵌套函数。在这样的情形中,非局部的控制流也不允许在lambda 函数中。为了表明,lambda 参数需要有 InlineOptions.ONLY_LOCAL_RETURN 注解:

    1. inline fun f(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) body: () -> Unit) {
    2. val f = object: Runnable {
    3. override fun run() = body()
    4. }
    5. // ...
    6. }

    内联 lambda 不允许用 break 或 continue ,但在以后的版本可能会支持。

    1. fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
    2. var p = parent
    3. while (p != null && !clazz.isInstance(p)) {
    4. p = p?.parent
    5. return p as T
    6. }

    现在,我们创立了一颗树,并用反射检查它是否是某个特定类型。一切看起来很好,但调用点就很繁琐了:

    我们想要的仅仅是给这个函数传递一个类型,即像下面这样:

    1. myTree.findParentOfType<MyTreeNodeType>()

    为了达到这个目的,内联函数支持具体化的类型参数,因此我们可以写成这样:

    1. inline fun <reified T> TreeNode.findParentOfType(): T? {
    2. var p = parent
    3. while (p != null && p !is T) {
    4. p = p?.parent
    5. }
    6. return p as T
    7. }

    我们用 refied 修饰符检查类型参数,既然它可以在函数内部访问了,也就基本上接近普通函数了。因为函数是内联的,所以不许要反射,像 !is `as`这样的操作都可以使用。同时,我们也可以像上面那样调用它了 myTree.findParentOfType<MyTreeNodeType>()

    尽管在很多情况下会使用反射,我们仍然可以使用实例化的类型参数 javaClass() 来访问它:

    1. inline fun methodsOf<reified T>() = javaClass<T>().getMethods()
    2. fun main(s: Array<String>) {
    3. println(methodsOf<String>().joinToString('\n'))

    普通的函数(没有标记为内联的)不能有实例化参数。