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

我在一个库中遇到了一个问题,我正在写零垃圾回收。 我写了一个myFunction函数,但我有一个问题,我不能调用函数,除非我扩展类(在这种情况下) 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的实例可以与显式或隐含的接收器一起被推断出来。 Kotlin无法同时指定类的实例和不同的接收者。 只有当你指定一个,而另一个可以隐含时,你才能做到这一点。

如果我们嘲笑它,问题可能会更加明显:

 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的实例由类本身满足,并且在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.将类内扩展移到类的外面,以便它不需要实例:

 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被称为成员扩展函数,因为它是类A的成员,也是类B的扩展。 foo里面有两个接收器可用:

  • this@A被称为调度接收器,
  • this@foo或者简单的叫做扩展接收器。

你怎么能同时指定A和B? “Instance A receiver B call foo()”没有语法。

其实有这样的语法,你只需要有A隐含的调度接收器:

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

在这里,您将A实例指定为隐式调度接收方,将B实例指定为显式扩展接收方。

如何从问题的类看起来像:

 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成员扩展,因为它不使用两个接收器内。 只要使它成员或扩展,而不是两个,正如这个答案所示。