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
你怎么能同时指定A
和B
? “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
成员扩展,因为它不使用两个接收器内。 只要使它成员或扩展,而不是两个,正如这个答案所示。