¿Cómo delegar la implementación a una propiedad en Kotlin?

Kotlin me permite implementar una interfaz delegando en un argumento de constructor primario como ese:

class Foo(xs : ArrayList<Int>) : List<Int> by xs { } 

Pero esto muestra el implementador de respaldo para el usuario. Delegar a un anónimo también parece estar bien:

 class Foo() : List<Int> by ArrayList<Int>() { } 

Esto oculta los detalles de la implementación, pero perdemos el acceso a las características que no proporciona la interfaz, que en este caso es la mutabilidad.

Por lo tanto, me gustaría delegar la implementación a una propiedad que no está en el constructor primario. Lo que me gustaría tener es similar a

 class Foo() : List<Int> by xs { val xs : List<Int> = ArrayList<Int>() } 

que no comstack

¿Es posible tener una propiedad definida explícitamente en el cuerpo de la class y aún así poder delegarle la implementación?

Esto no es posible actualmente. La expresión en la cláusula by se calcula solo una vez antes de la construcción de la class, por lo que no puede hacer reference a símbolos de esa class.

Hay una request en el rastreador de problemas para permitir esto, aunque es casi seguro que no va a ser compatible con Kotlin 1.0.

Una solución divertida que a veces funciona es hacer que la propiedad que desea sea un delegado, un parámetro constructor con el valor pnetworkingeterminado en su lugar. De esta forma será accesible tanto en la cláusula by como en el cuerpo de la class:

 class Foo(val xs: List<Int> = ArrayList<Int>()) : List<Int> by xs { fun bar() { println(xs) } } 

Sin embargo, tenga en count que xs in by xs se calcula solo una vez aquí, por lo que incluso si xs es una propiedad var , solo se usará el valor pnetworkingeterminado proporcionado en el constructor. No es una solución universal, pero a veces puede ser útil.

Ampliando la respuesta de Alexander Udalov, se me ocurrió una solución usando una class base privada

 private open class FooBase(protected val xs : MutableList<Int>) : List<Int> by xs { } class Foo() : FooBase(ArrayList()) { fun bar() { xs.add(5) } } 

Ahora puedo tener acceso a la propiedad que respalda la implementación de mi interfaz, pero no estoy restringido a las operaciones proporcionadas por esa interfaz mientras sigo ocultando la implementación real del usuario.

Nota: Aunque funciona, recibo la siguiente advertencia de IntelliJ IDEA 15 CE que surge de la inspección EXPOSED_SUPER_CLASS : EXPOSED_SUPER_CLASS : la visibilidad efectiva de la subclass 'público' debe ser la misma o less permisiva que su visibilidad efectiva de la superclass 'privada' . No estoy seguro de qué significa la parte obsoleta : si la advertencia se eliminará en el futuro o si no se comstackrá en algún momento. De todos modos, no tenemos que usar una class private open , abstract o simplemente open , porque incluso si el usuario puede crear una instancia de FooBase , no hay mucho que pueda hacer con ella.

Actualizar:

Actualmente hay una solución simple y compacta que no utiliza ningún comportamiento sospechoso:

 class Foo private constructor(private val xs: ArrayList<Int>) : List<Int> by xs { constructor() : this(ArrayList<Int>()) { } } 
  • ¿Cómo creo una instancia de un tipo genérico?
  • Elimina getters y setters del código de kotlin
  • ¿Cuál es la mejor manera en kotlin para que el método toString () de un object nulo devuelva una cadena vacía en lugar de "nulo"?
  • Cómo inyectar fábrica de dependencia transitoria con Kodein?
  • Spring Boot .mustache Extensión de file
  • ¿Cómo probar el método del presentador en base a un valor devuelto por Observable?
  • Basic Realm + Kotlin: RealmObject no está configurando valores pasados
  • Quiero abrir files desde carpetas
  • ¿Cuál es la syntax para Class <? extiende class_name> en kotlin?
  • Cómo devolver una interfaz como javawith Kotlin
  • LIBGDX: setPasswordMode no funciona