Присвоение не допускается при выражении?

В Java мы обычно можем выполнять присвоение в рамках условия while. Однако Котлин жалуется на это. Поэтому следующий код не компилируется:

val br = BufferedReader(InputStreamReader(
        conn.inputStream))

var output: String
println("Output from Server .... \n")
while ((output = br.readLine()) != null) { // <--- error here: Assignments are not expressions, and only expressions are allowed in this context
    println(output)
}

В соответствии с этим другим thread это кажется лучшим решением:

val reader = BufferedReader(reader)
var line: String? = null;
while ({ line = reader.readLine(); line }() != null) { // <--- The IDE asks me to replace this line for while(true), what the...?
  System.out.println(line);
}

Но это?

Ответ 1

Нет, лучший способ, ИМО, был бы

val reader = BufferedReader(reader)
reader.lineSequence().forEach {
    println(it)
}

И если вы хотите убедиться, что читатель правильно закрыт (как это было бы с оператором try-with-resources в Java), вы можете использовать

BufferedReader(reader).use { r ->
    r.lineSequence().forEach {
        println(it)
    }
}

Ответ 2

Вот самое короткое решение на базе stdlib, которое также безопасно закрывает читателя:

reader.forEachLine {
    println(it)
}

Ответ 3

И вот краткое общее решение в стиле Котлина Романа Елизарова:

while (true) {
    val line = reader.readLine() ?: break
    println(line);
}

Здесь break имеет тип Nothing, который не влияет на вывод типа для line.

Ответ 4

В случаях, когда вы просто хотите заменить while ((x = y.someFunction()) != null) вы можете использовать следующее:

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

generateSequence будет извлекать все значения одно за другим, пока не будет достигнут первый null. Вы можете заменить .forEach на reduce или fold (или что-либо еще, что кажется подходящим ;-)), если вы хотите сохранить последнее значение или суммировать значения в другом месте.

Однако для вашего конкретного случая использования вы можете просто использовать то, что показал JB Nizet в своем ответе, или использовать useLines:

reader.useLines {
  it.forEach(::println)
}

.forEachLine, вероятно, является следующим лучшим сокращенным решением для этой конкретной readLine -problem (уже здесь ответили), если вы знаете, что просто хотите прочитать все строки и затем остановиться.

Ответ 5

(Этот пример для цикла while) Надеюсь, что этот пример поможет вам..

Меняться от

while ((c = is.read(buffer))> 0) {sb.append(String (buffer, 0, c, Charset.forName(UTF8))))}

в

while ({c = is.read(buffer); c}()> 0) {sb.append(String (buffer, 0, c, Charset.forName(UTF8))))}