2016-09-19 51 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所建議的那樣,讓它成爲成員或擴展名,而不是兩者。