如何在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>
的泛型参数),因为签名在泛型擦除后会发生冲突。
然而,在你的情况下, Unit
是Any
子类型,并且由于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 }