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) { }
}
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
.
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)
}
}
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);
}
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.
I think this may help you:
input.buffered(1024).reader().forEachLine {
fos.bufferedWriter().write(it)
}
the simple way in kotlin is
if (kotlin.run{ a=b; a != c}){ ... }