How to convert Java assignment expression to Kotli

2019-01-18 02:39发布

问题:

Something in java like

int a = 1, b = 2, c = 1;
if ((a = b) !=c){
    System.out.print(true);
}

now it should be converted to kotlin like

var a:Int? = 1
var b:Int? = 2
var c:Int? = 1
if ( (a = b) != c)
    print(true)

but it's not correct.

Here is the error I get:

in " (a=b)" Error:(99, 9) Kotlin: Assignments are not expressions, and only expressions are allowed in this context

Actually the code above is just an example to clarify the problem. Here is my original code:

fun readFile(path: String): Unit { 
    var input: InputStream = FileInputStream(path) 
    var string: String = "" 
    var tmp: Int = -1 
    var bytes: ByteArray = ByteArray(1024) 

    while((tmp=input.read(bytes))!=-1) { } 
}

回答1:

As @AndroidEx correctly stated, assignments are not expressions in Kotlin, unlike Java. The reason is that expressions with side effects are generally discouraged. See this discussion on a similar topic.

One solution is just to split the expression and move the assignment out of condition block:

a = b
if (a != c) { ... }

Another one is to use functions from stdlib like let, which executes the lambda with the receiver as parameter and returns the lambda result. apply and run have similar semantics.

if (b.let { a = it; it != c }) { ... }

if (run { a = b; b != c }) { ... }

Thanks to inlining, this will be as efficient as plain code taken from the lambda.


Your example with InputStream would look like

while (input.read(bytes).let { tmp = it; it != -1 }) { ... }

Also, consider readBytes function for reading a ByteArray from an InputStream.



回答2:

Assignments are not expressions in Kotlin, thus you'll need to do it outside:

var a: Int? = 1
var b: Int? = 2
var c: Int? = 1

a = b
if (a != c)
    print(true)

For your other example with InputStream you could do:

fun readFile(path: String) {
    val input: InputStream = FileInputStream(path)
    input.reader().forEachLine {
        print(it)
    }
}


回答3:

As pretty much everyone here has pointed out, assignments are not expressions in Kotlin. However, we can coerce the assignment into an expression using a function literal:

val reader = Files.newBufferedReader(path)
var line: String? = null
while ({ line = reader.readLine(); line }() != null) {
    println(line);
}


回答4:

Java: (a = b) != c

Kotlin: b.also { a = it } != c


Around OP's question:

Unlike the accepted answer, I suggest using Kotlin's also function, instead of let:

while (input.read(bytes).also { tmp = it } != -1) { ...

Because T.also returns T (it) itself and then you can compare it with -1. This is more similar to Java's assignment as a statement.


See "Return this vs. other type" section, on this useful blog for details.



回答5:

I think this may help you:

 input.buffered(1024).reader().forEachLine {
            fos.bufferedWriter().write(it)
        }


回答6:

the simple way in kotlin is

if (kotlin.run{ a=b; a != c}){ ... }


标签: java kotlin