【问题标题】:Kotlin using lambda as initializerKotlin 使用 lambda 作为初始值设定项
【发布时间】:2019-06-06 09:09:54
【问题描述】:

所以我有以下两难境地。这不是关于什么不起作用的问题,而是关于什么会更优雅/更好的做法以及为什么。

所以,我们知道init 块,初始化逻辑进入其中。也许你打开一个文件或从配置文件中读取一些常量,也许你基于一些使用构造函数参数的更复杂的算法来设置一些属性。

但是,如果您的某个/某些属性确实需要一点逻辑、琐碎的逻辑(例如验证参数或类似的事情),该怎么办。而且这个逻辑只与那个特定的属性有关,与其他属性没有交互?

例如:

class MyCircularQueue(k: Int) {

    private val arr = { 
        if (k < 1) 
            throw IllegalArgumentException("k must be at least 1") 
        else  
            Array(k) { 0 }
    }()

    private var head = 0
    private var tail = 0
    private var empty = true

}

这里arr需要初始化为0s的数组,但是如果k小于1显然会有问题。需要一个非常短的初始化逻辑,只是一个简单的检查,抛出一个异常或初始化数组。没有与其他属性的交互,没有复杂的逻辑,只是一个极其微不足道的检查或逻辑。

在这种情况下,我想知道将琐碎的初始化逻辑放在“临时”代码块(当场调用的 lambda)中是否更好。好处是声明和初始化逻辑将在同一个地方,不需要分开,我认为这种方式更具可读性。

所以在我写完这篇文章后,我想知道是否有其他人对非常简单的初始化逻辑有这个问题,但我真的找不到任何关于它的东西。

所以底线:这样可以吗?是好的做法,还是至少不是不好的做法?是否有意义?在 Kotlin 中是否有更好和/或官方的方式来做到这一点?

【问题讨论】:

    标签: kotlin properties initialization readability


    【解决方案1】:

    函数变通方法不是必须的,if是一个表达式并返回一个值,所以可以简化:

    private val arr =
        if (k < 1)
            throw IllegalArgumentException("k must be at least 1")
        else
            Array(k) { 0 }
    

    另外,Kotlin 在标准库中附带了许多功能性 API,可以帮助创建简洁的单行。在这种情况下,您可以这样做:

    private val arr =
         k.takeIf { it > 0 }?.let { Array(k) { 0 } } ?: throw IllegalArgumentException("k must be at least 1")
    

    【讨论】:

    • 那一刻我完全忘记了 if 实际上是一种表达方式,谢谢!而第二种方法就是哇
    【解决方案2】:

    正如 s1m0nw1 的回答所说,您在这里并不需要它,但是当您需要它时它会很有用,例如初始化程序中的局部变量。

    在这种情况下,我不会使用 () 来调用 lambda,而是使用 run 来很好地内联它并且更明显,例如

    private val arr = run {
      val temp1 = ...
      val temp2 = ...
      arrayOf(temp1, temp2)
    }
    

    【讨论】:

    • 忘记了run。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-05-23
    • 2016-09-05
    • 2020-09-21
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    相关资源
    最近更新 更多