如何在 kotlin 中简化此代码?

How can I make this code simpler in kotlin?

我自学了编程,然后决定使用 Kotlin。

我编写了一个解决三角形的简单程序,效果很好,但我的代码丑陋且重复。

你能帮我改进一下吗,任何建议都会有帮助,因为即使我的代码有效,它看起来也不正确。

    private fun validateNumbers() {
        if(binding.etHip.text.toString().isNotEmpty()){
            Hip = (binding.etHip.text.toString()).toFloat()
        }
        if(binding.etAdj.text.toString().isNotEmpty()){
            Adj = (binding.etAdj.text.toString()).toFloat()
        }
        if(binding.etOpp.text.toString().isNotEmpty()){
            Opp = (binding.etOpp.text.toString()).toFloat()
        }
        if(binding.etAngle.text.toString().isNotEmpty()){
            Angle = (binding.etAngle.text.toString()).toFloat()
        }

    }


    private fun countSelected() {
        binding.cbHyp.setOnCheckedChangeListener { compoundButton, b ->
            if(binding.cbHyp.isChecked){
                numberCB++
            }
            else{
                numberCB--
            }
        }

        binding.cbAdj.setOnCheckedChangeListener { compoundButton, b ->
            if(binding.cbAdj.isChecked){
                numberCB++
            }
            else{
                numberCB--
            }
        }

        binding.cbOpp.setOnCheckedChangeListener { compoundButton, b ->
            if(binding.cbOpp.isChecked){
                numberCB++
            }
            else{
                numberCB--
            }
        }

        binding.cbAngle.setOnCheckedChangeListener { compoundButton, b ->
            if(binding.cbAngle.isChecked){
                numberCB++
            }
            else{
                numberCB--
            }
        }


    }


这个怎么样?逻辑是一样的。它只是在语法上进行了简化。

private fun validateNumbers() = with(binding) {
    if (etHip.text.toString().isNotEmpty()) Hip = (etHip.text.toString()).toFloat()
    if (etAdj.text.toString().isNotEmpty()) Adj = (etAdj.text.toString()).toFloat()
    if (etOpp.text.toString().isNotEmpty()) Opp = (etOpp.text.toString()).toFloat()
    if (etAngle.text.toString().isNotEmpty()) Angle = (etAngle.text.toString()).toFloat()
}

private fun countSelected() = with(binding) {
    setOf(cbHyp, cbAdj, cbOpp, cbAngle).forEach {
        it.setOnCheckedChangeListener { if (it.isChecked) numberCB++ else numberCB-- }
    }
}

对于这两个函数,您可以将它们包装在 with(binding) 中,这样您就不必一直写 binding.

对于 validateNumbers,您可以使用 toFloatOrNull() 将值转换为 Float,或者如果它不作为 Float 求值则为 null(例如空字符串无效)。然后您可以使用 Elvis 运算符 ?: 来提供默认值。所以如果你不想改变这个值,它可以 return 本身。

此外,由于您重复执行此操作,因此您可以创建一个从 EditText 获取值的快捷方式。这是TextView的一种,所以你可以把它写成TextView的扩展。

private fun TextView.toFloatOrNull() = text.toString().toFloatOrNull()

private fun validateNumbers() = with(binding) {
    Hip = etHip.toFloatOrNull() ?: Hip
    Adj = etAdj.toFloatOrNull() ?: Adj
    Opp = etOpp.toFloatOrNull() ?: Opp
    Angle = etAngle.toFloatOrNull() ?: Angle
}

使用 countSelected() 因为他们都在他们的听众中做完全相同的事情,所以你可以给他们所有相同的听众。 lambda 中的第二个参数是它是否刚刚被检查,所以你也可以稍微简化一下逻辑。您可以使用 listOf(...).forEach 来获取它们。

fun countSelected() = with(binding) {
    val listener = OnCheckedChangeListener { _ isChecked ->
        if (isChecked) numberCB++ else numberCB--
    }
    listOf(cbHyp, cbAdj, cbOpp, cpAngle).forEach {
        it.onCheckedChangeListener = listener
    }
}

我还会将函数名称更改为更具描述性的名称。您的函数不计算某些东西...它正在设置复选框来计算它们自己。

注意,属性 和变量名按照惯例应以小写字母开头。这将使您的代码更易于阅读。大写首字母通常保留用于 class 和接口名称。 (它们也用于其他一些语言中的函数名称,但您不应该在 Kotlin 中这样做,否则它们会与构造函数调用混淆。)