Kotlin 内联方法不可见,除非扩展 Class

Kotlin inline Method is not Visible Unless Extending the Class

我 运行 在我为零垃圾收集编写的库中遇到了一个问题。我写了一个 myFunction 函数,但我有一个问题,我无法调用该函数,除非我扩展 class (在这种情况下) RandomClass

package com.charlatano

fun main(args: Array<String>) {
    val hello = RandomClass<String>()
    hello.myFunction { // Unresolved reference: myFunction          
    }
}

class myClass {
    private val list = RandomClass<String>()

    fun loop() {
        list.myFunction { // Unresolved reference: myFunction               
        }
    }
}

class myClassInherit : RandomClass<String>() {      
    private val list = RandomClass<String>()

    fun loop() {
        list.myFunction { // Compiles without issue             
        }
    }
}

open class RandomClass<out E>() {       
    fun iterator(): Iterator<E> {
        TODO()
    }

    inline fun <E> RandomClass<E>.myFunction(action: (E) -> Unit): Unit {
        for (e in iterator()) action(e)
    }       
}

这是错误:

Error:(23, 8) Kotlin: Unresolved reference: myFunction

问题是您在 RandomClass 的不同接收器中为 RandomClass 的某个实例编写了扩展函数。因此它只能与 RandomClass 一起使用,其中 RandomClass 的实例 this 可以与显式或隐式接收者一起推断出来。在 Kotlin 中无法同时指定 class 的实例和不同的接收者。指定一个就可以,另一个可以隐含。

如果我们模拟一下,问题可能会更明显:

class A {
   inline fun B.foo() { ... }
}   

A().foo() <--- nope, need B().foo() within A()
B().foo() <--- nope, can't see B.foo() from outside A instance (scoped extension)
A::B.foo() <--- doesn't exist as syntax, I made this up

如何同时指定 AB? "Instance A receiver B call foo()" 没有语法。

但如果您已经在 A 内,例如:

class A {
   inline fun B.foo() { ... }

   fun bar() { B().foo() }  <-- all good!  We have A, we have B, and can call foo
}   

A 的实例由 class 本身满足,而接收者则由 Foo 之前创建的 B 的新实例调用。与您的代码唯一不同的是,您调用 A 实例和 B 接收器是同一件事,但它们是进行此类函数调用需要知道的两个参数。

在你的情况下,你有两个简单的选择来摆脱对实例和接收器的需要:

1.不要使 myFunction 成为扩展函数,只使其内联:

open class RandomClass<out E>() {
    fun iterator(): Iterator<E> {
        TODO()
    }

    inline fun myFunction(action: (E) -> Unit): Unit {
        for (e in iterator()) action(e)
    }
}

2。将内联扩展移到 class 之外,这样它就不需要实例了:

open class RandomClass<out E>() {
    fun iterator(): Iterator<E> {
        TODO()
    }
}

inline fun <E> RandomClass<E>.myFunction(action: (E) -> Unit): Unit {
    for (e in iterator()) action(e)
}

不管怎样,你都没有编译器错误了。

class A {
   inline fun B.foo() { ... }
}   

foo称为成员扩展函数,因为它是classA的成员,是classB的扩展。 foo 内部有两个接收器可用:

  • this@A被调用为dispatch receiver,
  • this@foo 或简称 this 称为扩展接收器。

How can you specify both A and B at the same time? There is no syntax for "Instance A receiver B call foo()".

实际上有这样的语法,你只需要将A作为隐式this dispatch receiver:

with(A()) {
   B().foo()
}

此处您将 ​​A 的实例指定为隐式调度接收器,将 B 的实例指定为显式扩展接收器。

问题 classes 会是什么样子:

val randomClass = RandomClass<Any>()
val anotherRandomClass = RandomClass<Any>()
with(randomClass) {
    // randomClass is both dispatch receiver and extension receiver
    myFunction {  }
    // randomClass is dispatch receiver and anotherRandomClass is extension receiver
    anotherRandomClass.myFunction {  }
}

但是在你的情况下没有必要做 myFunction 成员扩展,因为它没有在内部使用两个接收器。正如 建议的那样,只需将其设为成员或扩展,而不是同时设为两者。