Cómo sobrecargar constructores en kotlin difiere en el tipo de retorno lambda

Tengo dos constructores que son diferentes solo en su tipo de retorno lambda. ¿Hay alguna opción de cómo sobrecargarlos? Estaba intentando usar la anotación de JvmOverloads , pero no funcionó.

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

No puede definir constructores con firmas que difieran solo en parameters generics (en su caso, son parameters generics para Function1<in P1, out R> ) porque las firmas chocarían después del borrado de generics.

Sin embargo, en su caso, la Unit es el subtipo de Any , y dado que la Function<in P1, out R> es covariante en R , puede pasar una function que devuelva la Unit al segundo constructor, de modo que simplemente elimine la primera.

Ejemplo simplificado:

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

Para casos más complicados, considere cambiar a funciones de fábrica : a diferencia de los constructores, puede anotarlos con @JvmName para evitar el choque de firmas:

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

Cuando se dirige al backend de JVM, todas las classs de Kotlin se comstackn en bytecode de JVM. El problema con bytecode de java es tipo borrado . Esto significa que se elimina toda la información sobre los generics (es cuestión de Java, no de Kotlin).

Declaración de tipo funcional (transaction: Transaction) -> Unit es equivalente a usar este tipo: Función1 Function1<Transaction, Unit> . Sin embargo, para el bytecode de JVM, tanto Function1<Transaction, Unit> como Function1<Transaction, Any> son iguales.

Esto significa que ambos constructores tienen la misma firma en el mundo de JVM.

Puede "simular" constructores utilizando un 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) })) } } 

Y el uso se ve así:

 fun main(args: Array<String>) { val db = Database() MyClass(db, Handler { }) //real constructor MyClass(db){ } //version from companion object } 
  • Kotlin: ¿Cómo puedo invocar un campo lambda que tiene un tipo genérico de su class?
  • Poniendo un lambda genérico en un map
  • Kotlin lambda con varios parameters
  • Kotlin: ¿usar una lambda en lugar de una interfaz funcional?
  • Tipo de function con receptor en Scala
  • convert comparator en lambda en Kotlin
  • Kotlin no puede acceder a kotlin.jvm.functions.Function1 cuando llama a la function kotlin con java lambda
  • ¿Cómo declaro un parámetro de function para aceptar funciones que arrojan?
  • Kotlin y Jack no son compatibles (Android Studio 2.3.2)
  • Kotlin: comparar los valores de propiedad de diferentes objects objective con (fuera) reflexión
  • Usar interfaces funcionales con types de funciones en Kotlin