¿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>()) { } } 
  • Use NumberFormat.getCurrency en Kotlin Android
  • ¿Cómo se inyectan parameters de campo con nombre en Kotlin con Dagger 2?
  • Acceder a los ID de resources usando Kotlin y Anko
  • Determinando un pivote de ScaleAnimation
  • Kotlin: atribuye visibilidad al object complementario
  • Accesibilidad a la propiedad en Kotlin
  • Kotlin getParcelableArray del set de bashs no puede convertirlo en tipo personalizado
  • Reactive Spring 5 Nombre principal de security en Kotlin
  • ¿Podría explicarnos la divertida requestByZipCode?
  • Deserializador de logging para una list envuelta de tipo
  • Subclass de AsyncTask en Kotlin: no se puede usar el parámetro constructor principal dentro de onPostExecute