Destructuring Declarations in Kotlin

Destructuring declarations is a Kotlin feature that gives you a tool for easily extracting data from a collection in a simple and clean way. By arjuna sky kok.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Omitting Variables in Destructuring Declarations

You can omit the variables that you don’t want with an underscore. Using this approach, you avoid polluting namespace. Behind the scenes, Kotlin won’t call component2, component3 and component4.

Replace TODO 2 with the code below:

val (string1, _, _, _, string5) = stringList
println("$string1, $string5")

Build and run. You can see the values of string1 and string5.

The output of destructuring declarations of an array

Python inspired Kotlin in this case. In Python, underscore is a throwaway variable: you just want to ignore the values.

If you’re wondering why you couldn’t use different names for these throwaway variables, the answer is you could. But you have to use different names for more than one throwaway variable. For example, you could use variable names with one character like this:

val (string1, a, b, c, string5) = stringList
println("$string1, $string5")

In the code above, you ignore a, b and c. But somehow you have to store the extra information that there are three variables you have to ignore in the rest of the code. Using underscore is easier for your brain.

But what if you want to use the same name for each throwaway variable? For example, you want to use tmp as the name for every throwaway variable like this:

val (string1, tmp, tmp, tmp, string5) = stringList
println("$string1, $string5")

If you use the same name for more than one variable declaration, you’ll get conflicting declarations errors.

Good job! Now that you know how to use destructuring declarations, you’ll learn common use cases where you might want to use them.

Common Use Case of Destructuring Declarations

Destructuring declarations, although not very common in beginner code, can be helpful in a lot of situations and make your code better, in this section we will review common use-cases for them.

Replace TODO 3 with the following:

val (bitcoinFromFunction, btcFromFunction) = functionReturningPair()
println("$bitcoinFromFunction, $btcFromFunction")

Take a look at the function that is two lines above the code you just pasted fun functionReturningPair() : Pair = Pair("Bitcoin", "BTC"). The function is pretty straightforward, you are just returning a pair. In real life this kind of function would do some processing and then return the value, but for the example, it is very simple.

Build and run. You can see the value of bitcoinFromFunction and btcFromFunction.

The output of destructuring declarations of a function

Developers commonly use destructuring declarations when they want to return more than one value in a function and use them immediately after executing a function.

The alternative is collecting the return result with a collection data structure then later spliting it with the index operator or destructuring declarations. As shown in the code below, it’s not efficient:

val aPair = functionReturningPair()
val bitcoinFromFunction = aPair[0]
val btcFromFunction = aPair[1]
println("$bitcoinFromFunction, $btcFromFunction")

As you can see, the code is too verbose.

It’s common to return a collection from a function. For example, you may have a function that calculates the longitude and latitude of a location.

But outside the function, you may want to use the latitude and longitude separately instead of as a package. Destructuring declarations is handy in this situation.

Destructuring Declarations of A Map

Another data structure where you can use Destructuring Declarations is the iteration of a map. Maps are key-value pairs grouped in a collection. They are similar to an array, with the difference that you can name the key, instead of it being a sequential number.

Replace TODO 4 with this code:

for ((cryptoFullname, cryptoSymbol) in cryptoSymbolMap) {
    println("$cryptoFullname, $cryptoSymbol")
}

Build and run. You can see the key and value of every item in the map.

The output of destructuring declarations of a map

In the code above, cryptoSymbolMap is a map. You use destructuring declarations on the element while iterating the map by enclosing two variables separated by a comma in parentheses.

The first variable is the element’s key, while the second variable is the element’s value. It’s similar to the previous way of destructuring elements but you don’t use val or var.

When iterating a map with forEach, you use it the same way.

Destructuring Declarations in a Lambda Function

Lambda functions are very common in Kotlin code and in most modern programming languages, the syntax of Lambda functions is { a, b -> a + b }. In this section, we will look at how destructuring declarations can be useful in this kind of function.

Replace TODO 5 with:

cryptoSymbolMap.forEach { (cryptoFullname, cryptoSymbol) ->
    println("$cryptoFullname, $cryptoSymbol")
}

Build and run. You can see the key and value of every item in the map.

The output of destructuring declarations of a map with forEach

In the code above, forEach accepts a lambda that accepts a parameter. You use destructuring declarations on this parameter to extract them into two variables.

The type of the variable as the result of each iteration is Entry, which is a type that represents a key/value pair inside a Map. It has methods you’re familiar with such as: component1 and component2.

If you read the definition of component1, you’ll see the method returns the key component of this entry. Likewise, if you read the definition of component2, you’ll see the method returns the value component of this entry. There’s also a method to convert the entry to a pair.

Destructuring Declarations in Lambda

There’s a difference between a lambda that accepts two parameters and a lambda that accepts one parameter. You can use destructuring declarations inside the lambda that accepts one parameter.

Look at an example of a lambda with two parameters:

val lambdaCrypto = { name: String, symbol: String ->
    println("$name, $symbol")
}
lambdaCrypto("Bitcoin", "BTC")

In the lambda above, you call the lambda with two parameters: name and symbol, which are of the type String.

Now, look at an example of the same lambda with only one parameter. You use destructuring declarations on that parameter to extract them into two variables.

Replace TODO 6 with:

val lambdaCrypto2 = { (name: String, symbol: String): Parameter ->
    println("$name, $symbol")
}
lambdaCrypto2(param)

Build and run. You can see the values of name and symbol.

The output of destructuring declarations in lambda

In the code above, notice parentheses enclose two variables, while there are none in the lambda that accepts two variables.

If you come from a Python background, you may wonder whether you can destructure or unpack the arguments when calling the function as opposed to doing it inside the function like this:

lambdaCrypto(*Pair("Bitcoin", "BTC"))

There’s a spread operator in Kotlin. However, it’s not as flexible as the spread operator in Python. Because of that, you’ll get an error. You can only apply the spread operator in a vararg position.