Невозможно вызвать функцию из блока 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. Хотя я не хочу помещать код этой функции в блок init, потому что неясно, что делает код, и имя функции говорит об этом очень хорошо.
Что я могу сделать в таких случаях? Я хотел бы сохранить мой код в чистоте, это самый важный момент!
1 ответ
Одним из способов решения этой проблемы является использование чистых функций для инициализации полей:
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 }