【问题标题】:What is Kotlin equivalent for Java "assign and check"? [duplicate]Java“分配和检查”的Kotlin等价物是什么? [复制]
【发布时间】:2019-01-31 08:10:16
【问题描述】:

在 Java 中,有时我会编写如下代码:

 String obj = null;
 while ((obj = getObject()) != null) {
    // do smth with obj
 }

在 Kotlin 中显示编译时错误:

赋值不是表达式,在此上下文中只允许使用表达式

在 Kotlin 中最好的等价物是什么?

【问题讨论】:

  • (我知道你说过不要建议“更好”的方法,但就是这样:))
  • @FedericoklezCulloca 我认为 OP 以 readLine 为例,而不是读取行的方式
  • @Lino 对,这只是“分配和检查”的一个例子。更新了问题。
  • 来自:discuss.kotlinlang.org/t/…,您可以使用:while ({ line = readLine(); line }() != null)
  • @4ntoine 明白了。投票决定重新开放。

标签: java kotlin


【解决方案1】:

我宁愿放弃幻想,用老派的方式来做,这是最直观的。

 var obj = getObject();
 while (obj != null) {
    // do smth with obj
    obj = getObject();
 }

【讨论】:

  • 唯一遗憾的是你基本上写了两次相同的代码......而且你在while-loop中做的越多它被隐藏的越多...... :-/跨度>
【解决方案2】:

最简单的临时解决方案可能是

while(true) {
    val obj = getObj() ?: break
}

但是,IMO 最好使用专门的辅助函数来处理特殊情况。例如,可以使用帮助器 readLines 逐行读取文件,如answer 中对类似问题的解释:

reader.forEachLine {
    println(it)
}

【讨论】:

  • 我不太喜欢 while(true) 的休息时间。我认为这不是一个好习惯,因为它违反直觉,并且难以调试。有时它可能对不常见的情况很有用,但它是不寻常的......
  • getObj() 替换为reader.readLine(),您的答案与之前重复的问题相同,... (stackoverflow.com/a/43557893/6202869)(但:我没有否决)
【解决方案3】:

如果您只想替换 while ((x = y.someFunction()) != null),您可以使用以下代码:

generateSequence { y.someFunction() }
          .forEach { x -> /* what you did in your while */ }

generateSequence 将一个一个地提取所有值,直到达到第一个 null。如果您想保留最后一个值或将这些值总结为其他值,您可以将 .forEach 替换为 reducefold(或其他任何似乎合适的东西;-))。

如果您需要检查其他内容,您可以添加 takeIf 之类的内容,例如:

generateSequence { y.someFunction().takeIf { /* yourCondition... */ } }

基本上只是重复我也提到过的here

【讨论】:

  • 为什么?我在那里添加了一些关于useLines 等的内容,这在这里并不真正相关......但我也认为这是链接问题的重复问题......
  • 啊,是的,我刚才看到了,看起来几乎一样,所以我才提到它
【解决方案4】:

我已经修改并提出了一个简洁的通用辅助函数:

inline fun <T> (() -> T?).untilNull(action: (T) -> Unit) { 
    while (true) action(this() ?: break) 
}

可以这样调用:

::getObject.untilNull { /* do something with "it" */ }

你当然可以不使用这个辅助函数而只使用while

while(true){
    val result = getObject() ?: break
    // do something with "result"
}

另一种解决方案是创建一个内联 lambda,然后立即调用它:

var result = null
while ({ result = getObject(); result }() != null){
    // do something with "result"
}

如果您先“保存” lambda,这可能会得到优化:

var result = null
var assignment = { result = getObject(); result };
while (assignment() != null){
    // do something with "result"
}

【讨论】:

  • hmm...除了untilNull,我还看到了这个答案的所有变体here...老实说...untilNull-usage 看起来有点对我来说很奇怪......
  • @Roland 是的,这很奇怪,因为它结合了很多不同的东西,内联、泛型、扩展函数、lambda,当然还有 elvis 运算符和 break。它可以写得更冗长,但我认为这是人们想要遵循的主要代码风格
  • 说到影响:::getObject().untilNull 的影响是什么...untilNullinline,所以block 可能还可以...但是::getObject() 本身呢? ;-) 你提到的关于Stream/Sequence 的开销(当然取决于用例)通常可以忽略不计......你得到的好处:可读性,短路等往往超过了缺点...... .
  • @Lino 我认为你的最后一个更好的选择是while (run { result = getObject(); result != null }) ...保存 lambda。然后它会被内联(并且 IMO 更具可读性)。
  • @Roland ::getObject 也是 inline fun 的函数参数,它也会被内联。
【解决方案5】:

怎么样:

while (getObject().apply { obj = this } != null) {
    // ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-10
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 2010-11-29
    • 2012-08-03
    • 1970-01-01
    相关资源
    最近更新 更多