Detailed Explanation of Automatic Type Conversion of Kotlin

  • 2021-12-05 07:32:03
  • OfStack

Preface

The official version of Kotlin 1.4 was released long ago. There have been countless articles about "visible" new features, such as SAM transformations, optional commas at the end of parameter lists, and so on. So this article intends to introduce one of the perhaps little-known new features that the official team of Kotlin secretly stuffed into 1.4.

But talking about these things alone will make the article too thin, so I plan to pull up other similar things to make up the number of words.

The version of Kotlin used in this article is Kotlin 1.4.

What this article is going to talk about

Just look at the topic. Automatic type conversion in Kotlin (automatic type conversion). What we are talking about here is not something related to subtypes, such as "converting an String into Any and then into String", nor is it Smart Cast, but a conversion between two incompatible types, such as Int into Long, as shown below.

Numerical conversion

1 In general, in Kotlin we cannot assign an Int type to an Long type variable directly, as in Java 1, because there is no subtype relationship between them. You will get 1 compilation error like the following:


val int: Int = 555
val long: Long = int //  Compilation error! 
println(long)

You need to call the toXXX functions provided to you by the standard library to convert numeric values to other types of numeric values.


val int: Int = 555
val long: Long = int.toLong() // OK
println(long)

The official team of Kotlin has said that they don't like implicit (implicit), and implicit type conversion of numeric values is also included. As a result, when using Kotlin to do some numerical operations, it sometimes writes some code that looks extremely painful.

Bennyhuo: That is, sometimes write some code with more calculations, the full toFloat toDouble.

In general, we can use @ Suppress to do things:


val int: Int = 233
@Suppress("TYPE_MISMATCH")
val long: Long = int
println(long) // 233

This code can run, and you can really see the instruction I2L that turns Int into Long from ByteCode.

But I'm not sure if the other target of Kotlin will work like this, and I don't guarantee that it won't go wrong at all. (Here is a disclaimer about @ Suppress, please make up your own brain)

SAM Conversion

The SAM conversion is also an automatic type conversion. It converts an lambda expression (with a function type) to a specific interface type.


fun interface ISome {
 fun some()
}

fun useSome(some: ISome) {}

useSome { println("some") }

I have a more detailed introduction in my other article.

If readers disagree with this statement, they can choose to skip this section.

Coercion to Unit

We all know that the lambda expression of Kotlin uses the value of the last expression as the return value of lambda. For example:


val block = { "yeah" }

The type of block is ()- > String.

Then let's look at this situation:


fun test(block: () -> Unit) {
 println(block())
}

test { "yeah" } //  Output  Unit

I believe many people are familiar with this writing.

In the eyes of some beginners, this looks like putting a ()- > An lambda of type String is passed to the lambda that requires ()- > A function of type Unit.

This is coercion to unit, a feature that has existed for a long time. It can be understood that the compiler automatically adds a line of Unit to the end of the lambda expression, and puts what should be ()- > String type lambda becomes ()- > Unit type.

In Kotlin 1.4, this feature has evolved, and you can even write this:


fun test(block: () -> Unit) {
 println(block())
}

fun some(): String {
 return "str"
}

//  Need  Kotlin 1.4  Version 
test(::some) //  Output  Unit

The compiler will help you put ()- > Function references of type String are converted to ()- > Unit.

Unit Conversion

Warning: This is an unfinished feature!

Add the compiler argument-XXLanguage: + UnitConversion, and you open up an unfinished new feature that the official Kotlin team sneaked into version 1.4.

This feature allows you to write code like this:


fun test(block: () -> Unit) {
 println(block())
}

fun some(block: () -> String) {
 test(block) //  Here's the point 
 //  If you don't add that compiler parameter, you will report an error 
}

fun main() {
 some { "str" }
 //  Theoretically, it will output  Unit
}

In the function some, put 1 ()- > String is passed to the test function, and it can be seen that this feature is similar to coercion to unit.

Theoretically, such code will output Unit when it runs, but at present, because the code generation of this feature is not written well, it will not get the expected results.

In addition, when this feature is turned on, ()- > String will not become ()- > Subtypes of Unit, which are still two incompatible types.

Suspend Conversion

Warning: This is an unfinished feature!

This is the second Kt official team to sneak into the 1.4 version of the unfinished new feature.

For example, we have one function like this:


fun test(f: suspend () -> Unit) {
 // do something with f
}

We can call it this way:


test { println("hi") } 

But this won't work:


val int: Int = 555
val long: Long = int.toLong() // OK
println(long)
0

The compiler will tell you the type mismatch, f is ()- > Unit type, test function requires suspend ()- > Parameters of type Unit.

When you add the compiler parameter-XXLanguage: + SuspendConversion, you can compile the above code.

That is to say, this feature can help you convert the value of ordinary function type into suspend function type.

Of course, because this is an unfinished function, even if it can be compiled, it will still explode when running.

This feature may be completed in Kotlin 1.5, but don't expect it.

End

I don't want to discuss such topics as "why add this strange feature".

It is undeniable that these new features may not be used once in a limited programmer's career. The problems mentioned above also have corresponding workaround, and you can write equivalent code without new features, but it is not so elegant (


Related articles: