2016-09-21 48 views
3

我有兩個只在lambda返回類型中有所不同的構造函數。有什麼選擇如何超載他們?我試圖使用JvmOverloads註釋,但它不起作用。如何重載kotlin中的構造函數在lambda返回類型中有所不同

constructor(db : Database, handler: (transaction: Transaction) -> Unit) : this(db, Handler<Transaction>({handler.invoke(it)})) 

@JvmOverloads 
constructor(db : Database, handler: (transaction: Transaction) -> Any) : this(db, Handler<Transaction>({handler.invoke(it)})) 

回答

4

無法定義與區別僅在通用參數簽名的構造函數(在你的情況,這是通用的參數Function1<in P1, out R>),因爲簽名會後仿製藥擦除衝突。

然而,你的情況是UnitAny亞型,而且由於Function<in P1, out R>is covariant on R,你可以通過返回Unit給第二個構造函數,所以只是刪除第一個。

簡單的例子:

class C(val action: (Int) -> Any) 

fun main(args: Array<String>) { 
    val f: (Int) -> Unit = { println(it) } 
    C(f) 
} 

對於更復雜的情況下,consider changing to factory functions:不像構造函數,你可以用@JvmName註釋他們避免簽名衝突:

@JvmName("createCUnit") 
fun createC(f: (Int) -> Unit) = C(f) 

fun createC(f: (Int) -> Any) = C(f) 
3

當目標JVM後臺,所有科特林類被編譯爲JVM字節碼。 java的字節碼的問題是type erasure。這意味着關於泛型的所有信息都被刪除(這是Java的問題,而不是Kotlin的問題)。

聲明功能類型(transaction: Transaction) -> Unit等價於使用此類型:Function1<Transaction, Unit>。但是,對於JVM字節碼,Function1<Transaction, Unit>Function1<Transaction, Any>都是相同的。

這意味着您的構造函數在JVM世界中都具有相同的簽名。

可以 「模擬」 的構造函數使用companion object

class MyClass { 
    constructor(db: Database, h: Handler<Transaction>) 

    companion object { 
     operator fun invoke(db: Database, handler: (transaction: Transaction) -> Unit) = MyClass(db, Handler<Transaction>({ handler.invoke(it) })) 

     @JvmName("alternative_constructor") 
     operator fun invoke(db: Database, handler: (transaction:  Transaction) -> Any) = MyClass(db, Handler<Transaction>({ handler.invoke(it) })) 
    } 
} 

和使用情況是這樣的:

fun main(args: Array<String>) { 
    val db = Database() 

    MyClass(db, Handler { }) //real constructor 
    MyClass(db){ } //version from companion object 
} 
相關問題