Sometimes it is convenient to destructure an object into a number of variables, for example:
val (name, age) = person
This syntax is called a destructuring declaration. A destructuring declaration creates multiple variables at once. We have declared two new variables: name
and age
, and can use them independently:
println(name) println(age)
A destructuring declaration is compiled down to the following code:
val name = person.component1() val age = person.component2()
The component1()
and component2()
functions are another example of the principle of conventions widely used in Kotlin (see operators like +
and *
, for-loops etc.). Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it. And, of course, there can be component3()
and component4()
and so on.
Note that the componentN()
functions need to be marked with the operator
keyword to allow using them in a destructuring declaration.
Destructuring declarations also work in for-loops: when you say:
for ((a, b) in collection) { ... }
Variables a
and b
get the values returned by component1()
and component2()
called on elements of the collection.
Let's say we need to return two things from a function. For example, a result object and a status of some sort. A compact way of doing this in Kotlin is to declare a data class and return its instance:
data class Result(val result: Int, val status: Status) fun function(...): Result { // computations return Result(result, status) } // Now, to use this function: val (result, status) = function(...)
Since data classes automatically declare componentN()
functions, destructuring declarations work here.
NOTE: we could also use the standard class Pair
and have function()
return Pair<Int, Status>
, but it's often better to have your data named properly.
Probably the nicest way to traverse a map is this:
for ((key, value) in map) { // do something with the key and the value }
To make this work, we should
iterator()
function;component1()
and component2()
.And indeed, the standard library provides such extensions:
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = entrySet().iterator() operator fun <K, V> Map.Entry<K, V>.component1() = getKey() operator fun <K, V> Map.Entry<K, V>.component2() = getValue()
So you can freely use destructuring declarations in for-loops with maps (as well as collections of data class instances etc).
If you don't need a variable in the destructuring declaration, you can place an underscore instead of its name:
val (_, status) = getResult()
The componentN()
operator functions are not called for the components that are skipped in this way.
You can use the destructuring declarations syntax for lambda parameters. If a lambda has a parameter of the Pair
type (or Map.Entry
, or any other type that has the appropriate componentN
functions), you can introduce several new parameters instead of one by putting them in parentheses:
map.mapValues { entry -> "${entry.value}!" } map.mapValues { (key, value) -> "$value!" }
Note the difference between declaring two parameters and declaring a destructuring pair instead of a parameter:
{ a -> ... } // one parameter { a, b -> ... } // two parameters { (a, b) -> ... } // a destructured pair { (a, b), c -> ... } // a destructured pair and another parameter
If a component of the destructured parameter is unused, you can replace it with the underscore to avoid inventing its name:
map.mapValues { (_, value) -> "$value!" }
You can specify the type for the whole destructured parameter or for a specific component separately:
map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" } map.mapValues { (_, value: String) -> "$value!" }
© 2010–2018 JetBrains s.r.o.
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/multi-declarations.html