如何在kotlin中重载构造函数在lambda返回类型中有所不同

我有两个不同的lambda返回类型的构造函数。 有什么选择如何超载他们? 我试图使用JvmOverloads注释,但它没有工作。

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)})) 

你不能定义只有泛型参数不同的签名的构造函数(在你的情况下,它是Function1<in P1, out R>的泛型参数),因为签名在泛型擦除后会发生冲突。

然而,在你的情况下, UnitAny子类型,并且由于Function<in P1, out R>R上是协变的 ,所以可以传递一个返回Unit的函数给第二个构造函数,所以只需要移除第一个。

简单的例子:

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

对于更复杂的情况,请考虑更改为工厂函数 :与构造函数不同,您可以使用@JvmName进行注释以避免签名冲突:

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

针对JVM后端时,所有Kotlin类都被编译为JVM字节码。 Java的字节码的问题是类型擦除 。 这意味着关于泛型的所有信息都被删除了(这是Java的问题,而不是Kotlin的问题)。

声明功能类型(transaction: Transaction) -> Unit等同于使用此类型: Function1<Transaction, Unit> 。 但是,对于JVM字节码, Function1<Transaction, Unit>Function1<Transaction, Any>是相同的。

这意味着你的构造函数在JVM世界里都有相同的签名。

您可以使用companion object来“模拟”构造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 }