let
If you use let, you ask Kotlin to create an invisible function with a parameter.
1.let { println(5) }
//changes to:
fun func(it : Int) {
println(5)
}
func(1)
Do you see the it? That's the name of the parameter.
Therefor, you can use it inside let.
1.let { println(it) }
//changes to
fun func(it : Int) {
println(it)
}
func(1)
Now, the function returns something too, namely the result of the last statement.
In this case, it's just Unit, or void in Java (emptyNess):
fun func(it : Int) : Unit {
return println(it)
}
func(1)
If we take another example, it will be clearer:
val a = 5.let { 3 + it }
//changes to
fun func(it: Int) : Int {
return 3 + it
}
val a = func(5)
?.let
?. is very simple:
val b = a?.foo()
//changes to:
val b = if (a == null) a else a.foo()
?.let is exactly the same:
val b = a?.let { it+3 }
//changes to
fun func(it: Int){
it + 3
}
val b = if (a == null) null else func(a)
inline
Kotlin is smart. it actually uses an inline function for let.
An inline function is a function that actually doesn't exist.
Instead, the code is copy pasted into the real code.
The parameters are just variables with random names.
so
val b = a?.let { it + 3 }
//is actually changed to
val b = if (a == null) null else {
val ac432cd = a
ac432cd + 3
}
simplyfication
roomGrid[gridX][gridY - 1]?.let { room?.setNeighbor(Room.SOUTH, it) }
step 1
// I would check room first:
if (room != null) {
roomGrid[gridX][gridY - 1]?.let { room.setNeighbor(room.SOUTH, it) }
}
step 2
// flip the rooms (and directions)
if (room != null) {
roomGrid[gridX][gridY - 1]?.let{ it.setNeighbor(room.SOUTH, room) }
}
step 3
//remove let
if (room != null) {
roomGrid[gridX][gridY - 1]?.setNeighbor(room.SOUTH, room)
}
full code until now
// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY]
if (room != null) {
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
if (gridY < roomCountY - 1)
roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
if (gridX > 0)
roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
if (gridX < roomCountX - 1)
roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
}
}
}
step 4
At the moment, we test in the beginning if room
isn't null.
If it is, it skips the if-statement and continues with the next iteration.
We can tell to go to the next iteration immediately using the keyword continue.
// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY]
if (room == null) continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
...
}
}
step 5
last, kotlin has another language feature: ?:
val a = foo() ?: bar()
//will be rewritten to
val tmp = foo()
val a = if (tmp != null) tmp else bar()
Just as return
continue
skips immediately to the next variable.
This means that we can rewrite the code we wrote in step 4.
// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY] ?: continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
...
}
}
full code
// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY] ?: continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
if (gridY < roomCountY - 1)
roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
if (gridX > 0)
roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
if (gridX < roomCountX - 1)
roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
}
}
null
s? \$\endgroup\$