Escribir una interfaz Copyable más elegante que en Java

Intento escribir una interfaz que las classs puedan implementar para hacer que se pueda "copyr", un (seguro) Clonable.

En Java, haría algo como esto, usando generics recursivos:

public interface Copyable<C extends Copyable<C>> { C copy(); } public class Example implements Copyable<Example> { ... @Override public Example copy() { return new Example(this); //invoke copy constructor } } 

Obviamente, esto no es tan elegante, tanto los encabezados de Copyable como Example parecen Copyable complicados. ¿Hay una forma más elegante de lograr esto en Kotlin?

Aquí hay un bash de networkingucir la repetición genérica al sacrificar cierta security de tipo estático:

 interface Copyable { fun createCopy(): Copyable } inline fun <reified T : Copyable> T.copy(): T = createCopy() as T 

Podemos aprovechar las funciones de extensión para get el tipo genérico del receptor sin generics recursivos. Hacemos la function de extensión en línea para reificar el parámetro de tipo para que se verifique el lanzamiento y arroje una exception si la class implementadora no devuelve una instancia del mismo tipo.

Aquí hay un ejemplo de uso

 class Example(val a: String) : Copyable { constructor(e: Example) : this(ea) override fun createCopy() = Example(this) } fun main(args: Array<String>) { val copiedExample: Example = Example("a").copy() } 

Solución alternativa usando covarianza

Dependiendo de su caso de uso, ni siquiera necesita que el método de copy sea ​​genérico ya que podemos aprovechar la covarianza . Declara tus types como tal

 interface Copyable { fun copy(): Copyable } class Example(val a: String) : Copyable { constructor(f: Example) : this(fa) override fun copy() = Example(this) } 

Y como puede ver, el código val copiedExample: Example = Example("a").copy() aún se comstack. Esto se debe a que los methods sustituidos pueden devolver un tipo más específico que el método super y al usar las funciones de expresión únicas de Kotlin, el tipo que queremos se deduce automáticamente.

Sin embargo, esto puede provocar problemas si no está trabajando directamente con el tipo específico, pero digamos una subinterfaz de Copyable . El siguiente código no se comstack:

 interface CopyableIterable<T> : Iterable<T>, Copyable class Example : CopyableIterable<String> { constructor(e: Example) override fun copy() = Example(this) override fun iterator() = TODO() } fun foo(ci: CopyableIterable<String>) { val copy: CopyableIterable<String> = ci.copy() // error: type mismatch } 

La solución para esto es simple, anule también el método de copy en la subinterfaz:

 interface CopyableIterable<T> : Iterable<T>, Copyable { override fun copy(): CopyableIterable<T> } 
  • Cómo convertir la expresión de asignación de Java a Kotlin
  • Extender RxJava Observable en Kotlin con eliminación adecuada
  • ¿Cómo puedo ejecutar una sola testing de Android usando Kotlin?
  • Reino que devuelve datos obsoletos
  • Android LiveData: MutableData nunca está en estado activo
  • Android Kotlin: no se puede invocar el métodoNavigationItemSelected
  • Diferentes posiciones de destino cuando se usan diferentes tamaños de vista con ObjectAnimator
  • Cómo hacer una list KOTLIN con lists de corchetes API JSON
  • ¿Podría explicar este fragment de código en términos de código C #?
  • Forma correcta de get properties con la configuration de Kotlin-script para Gradle
  • Cambiar solo un método de una class de java a kotlin