2016-09-19 60 views
2

我遇到了一个问题,我正在编写一个用于零垃圾回收的库。我已经写了一个myFunction功能,但我有一个问题,我不能调用函数,除非我扩展类(在这种情况下)RandomClassKotlin内联方法不可见,除非扩展类

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 

回答

3

问题在于您在RandomClass的不同接收方内为某个RandomClass实例编写了扩展功能。所以它只能从RandomClass开始使用,其中实例thisRandomClass可以与显式或隐含的接收器一起推断出来。 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) 
} 

无论哪种方式,你都没有编译器错误了。

+0

真棒解释谢谢! –

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

foo被称为成员扩展功能,因为它是A类的成员和用于B类的扩展。里面的foo有两种接收器:

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派遣接收器:

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成员延伸,因为它不使用内部的两个接收器。就像this answer所建议的那样,让它成为成员或扩展名,而不是两者。