Implicit Receiver

双重 this

内部类和外部类的双重 this :

java:

public class OuterClass {
    int outerInt =1;
    int commonInt = 3;

    class InnerClass {
        int innerInt = 2;
        int commonInt = 4;

        public void   innerMethod() {
            System.out.println(innerInt);
            System.out.println(outerInt);
            // 内部类的this
            System.out.println(commonInt);
            // 外部类的this
            System.out.println(OuterClass.this.commonInt);
        }
    }
}

kotlin:

class OuterClass {
    var outerInt =1;
    var commonInt = 3;

    inner class InnerClass {
        var innerInt = 2;
        var commonInt = 4;

        fun innerMethod() {
            println(innerInt);
            println(outerInt);
            // 内部类的this
            println(commonInt);
            // 外部类的this
            println(this@OuterClass.commonInt);
        }
    }
}

Kotlin 中的 Implicit Receiver

multiply() 是 Int类型的扩展函数,所以需要对 Int 类型的对象才能调用它

同时 multiply() 也是 IntMultiplier 的成员函数,所以要求 IntMultiplier 对象调用它

也就是说,这里需要的是双重 receiver ,既要直接的Int,又要外部的 IntMultiplier ,缺一不可

class IntMultiplier(var time: Int =2) {
    fun Int.multiply()= time * this
}

fun main() {
    // 报错
    1.multiply()
    val intMultiplier = IntMultiplier()
    // 报错
    intMultiplier.multiply()
}

那我怎样调用 multiply() 函数?

专门创建一个函数,并给它设置一个函数类型的参数,并给这个函数类型的参数设置 receiver 类型,在函数体内调用这个函数参数

class IntMultiplier(var time: Int =2) {
    fun Int.multiply()= time * this

    fun runAsOuter(block: IntMultiplier.()-> Unit){
        block()
    }
}

fun main() {
    val intMultiplier = IntMultiplier()
    // runAsOuter 的大括号里就有了一个 IntMultiplier 的 this 了
    intMultiplier.runAsOuter {  // this: IntMultiplier
        3.multiply()
    }
}

甚至你可以这样

class IntMultiplier(var time: Int =2) {
    fun Int.multiply()= time * this

    fun runAsOuter(block: IntMultiplier.()-> Unit){
        block()
    }
}

fun Int.runAsOuter(block: Int.()-> Unit){
    block()
}

fun main() {
    val intMultiplier = IntMultiplier()
    // runAsOuter 的大括号里就有了一个 IntMultiplier 的 this 了
    intMultiplier.runAsOuter {  // this: IntMultiplier
        3.runAsOuter {
            multiply()
        }
    }
}

这样

class IntMultiplier(var time: Int = 2) {
    fun Int.multiply() = time * this

    fun runAsOuter(block: IntMultiplier.() -> Unit) {
        block()
    }
}

fun runAsInt(int: Int, block: Int.() -> Unit) {
    int.block()
}

fun main() {
    val intMultiplier = IntMultiplier()
    intMultiplier.runAsOuter {  // this: IntMultiplier
        runAsInt(3) {
            multiply()
        }
    }
}