Intereting Posts
Реализовать Hashmap с разными типами значений в Котлине Идиоматический способ чтения двоичного файла с Kotlin? Как ввести фабрику переходных зависимостей с Kodein? Kotlin: Создайте и передайте истинные массивы Java (для JNA) Параметр, заданный как non-null, равен null для данных в onActivityResult После добавления макетов программно, как изменить текстовое представление «#» нажатием кнопки Kotlin – Как установить время ожидания соединения с OkHttp Kotlin getActionView устарел? Как получить значение перечисления типа raw из класса enum и строки в kotlin Как конвертировать JS-код в Kotlin без ключевого слова 'new' Каков наилучший способ сделать снимок и показать результат с помощью Kotlin Anko? Получение абсолютного пути к файлу из содержимого URI для найденных изображений Как упростить реализацию по умолчанию функции kotlin Android 4.x VerifyError, вызванный методом Котлина Колин Спек Рамки сбой с / Gradle

Невозможно вызвать функцию из блока init из-за свойства val

Я хотел бы инициализировать свойства моего класса. Поскольку я сильно использую функциональные элементы Kotlin, я бы хотел поставить эти инициализации на хорошо названные функции, чтобы повысить читаемость моего кода. Проблема в том, что я не могу назначить свойство val, если код не находится в блоке init, а в функции, которая вызывается из блока init.

Можно ли разделить инициализацию класса на разные функции, если свойства являются vals?

Вот код:

val socket: DatagramSocket = DatagramSocket() val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() val broadcastAddresses: List<InetAddress> init { socket.broadcast = true val interfaceAddresses = ArrayList<InterfaceAddress>() collectValidNetworkInterfaces(interfaceAddresses) collectBroadcastAddresses(interfaceAddresses) } private fun collectValidNetworkInterfaces(interfaceAddresses: ArrayList<InterfaceAddress>) { NetworkInterface.getNetworkInterfaces().toList() .filter { validInterface(it) } .forEach { nInterface -> nInterface.interfaceAddresses.toCollection(interfaceAddresses) } } private fun collectBroadcastAddresses(interfaceAddresses: ArrayList<InterfaceAddress>) { broadcastAddresses = interfaceAddresses .filter { address -> address.broadcast != null } .map { it.broadcast } } 

Конечно, это не компиляция, потому что функция collectBroadcastAddresses пытается переназначить broadcastAddresses val. Хотя я не хочу помещать код этой функции в блок init, потому что не очевидно, что делает код, и имя функции говорит об этом очень красиво.

Что я могу сделать в таких случаях? Я хочу, чтобы мой код был чистым, это самый важный момент!

    Одним из способов решения проблемы является использование чистых функций для инициализации полей:

     class Operation { val socket = DatagramSocket().apply { broadcast = true } val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() val broadcastAddresses = collectBroadcastAddresses(collectValidNetworkInterfaces()) private fun collectValidNetworkInterfaces() = NetworkInterface.getNetworkInterfaces().toList() .filter { validInterface(it) } .flatMap { nInterface -> nInterface.interfaceAddresses } private fun validInterface(it: NetworkInterface?) = true private fun collectBroadcastAddresses(interfaceAddresses: List<InterfaceAddress>) { interfaceAddresses .filter { address -> address.broadcast != null } .map { it.broadcast } } } 

    Обратите внимание, как инициализация поля socket использует apply расширения.

    Я часто считаю полезным извлекать подпрограммы обработки коллекций в методы расширения:

     class Operation { val socket = DatagramSocket().apply { broadcast = true } val data: ByteArray = "Cassiopeiae server discovery packet".toByteArray() val broadcastAddresses = NetworkInterface.getNetworkInterfaces() .collectValidNetworkInterfaces { validInterface(it) } .collectBroadcastAddresses() private fun validInterface(it: NetworkInterface?) = true } fun Iterable<InterfaceAddress>.collectBroadcastAddresses(): List<InetAddress> = filter { address -> address.broadcast != null }.map { it.broadcast } fun Enumeration<NetworkInterface>.collectValidNetworkInterfaces(isValid: (NetworkInterface) -> Boolean = { true }) = toList() .filter { isValid(it) } .flatMap { nInterface -> nInterface.interfaceAddresses }