coding-style - 由于 val 属性,无法从 init block 调用函数

标签 coding-style kotlin

我想初始化我的类的属性。 因为我大量使用 Kotlin 的功能元素,所以我想将这些初始化放在命名良好的函数中,以提高代码的可读性。 问题是如果代码不在 init block 中,而是在从 init block 调用的函数中,我无法分配 val 属性。

如果属性是 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 block 中,因为代码在做什么并不明显,函数名就很好听了。

遇到这种情况我该怎么办?我想保持我的代码干净,这是最重要的一点!

最佳答案

解决该问题的一种方法是使用 pure functions初始化字段:

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 }

关于coding-style - 由于 val 属性,无法从 init block 调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34725155/

相关文章:

java - Kotlin 类文件无法在 IntelliJ for JUnit 中运行

java - 当从 Java 调用时,为什么必须在 void kotlin 函数中返回 Unit.INSTANCE,而不是 NULL?

coding-style - Resharper:如何在类的底部强制引入新的私有(private)字段?

javascript - 服务器端 Javascript 最佳实践?

java - 我应该在循环中内联长代码,还是将其移动到单独的方法中?

kotlin - Micronaut ExceptionHandler:使用状态代码和正文创建HttpResponse

Android Studio 3 Kotlin 版本

c - 带有类型或变量的 sizeof

wpf - 在 WPF 窗口的构造函数中,InitializeComponent() 之前应该做什么,之后应该做什么?

android - Jetpack 撰写 : Hoisitng click state from DropDownItems to DropDownMenu