官术网_书友最值得收藏!

Inline classes

There are times when you create a wrapper class for a type.  This incurs a runtime overhead because of the memory allocation. To mitigate this, Kotlin supports a special class named the inline class.  An inline class is a data class which has a single read-only property with the advantage of having a smaller memory footprint. When used in code, the compiler replaces the inline class instance, most of the time, with its underlying type value.

Consider writing a new function that makes a database call with the second argument being a timeout.  Instead of using a Long to express how long to wait for the operation to complete, you define an inline class as follows:

data class Payment(val id: String, val user: String, val amount: Double)
inline class Millis(val timeout:Long)

fun updatePayment(payment:Payment, timeout:Millis):Unit {
//update your storage
}

In order to enrich the API, you can define the following classes:

inline class Seconds(val timeout:Long){
fun toMillis():Millis = Millis(timeout * 1000)
}

inline class Minute(val timeout:Long){
fun toMillis():Millis= Millis(timeout * 1000 * 60)
}

inline class Hours(val timeout: Long) {
fun toMillis(): Millis = Millis(timeout * 1000 * 60 * 60)
}

Now you can call your code as follows:

updatePayment(payment, Seconds(10).toMillis())

There are a few rules to follow when using an inline class. While an inline class can inherit an interface, it cannot be inherited from. You can define properties and functions for an inline class, but you cannot have backing fields or an init block.

In most cases, the Kotlin compiler will use underlying types instead of wrappers to produce the most performant and optimized code. However, sometimes it is necessary to keep and use the wrapper class. As a rule of thumb, inline classes are boxed whenever they are used as another type.  The following is a code example defining a Timeout interface and an inline class for Milliseconds Timeout.  Then a few methods are defined to showcase when boxing is required:

interface Timeout

inline class MillisecondsTimeout(val l: Long) : Timeout

fun asInline(millis: MillisecondsTimeout) {}
fun <T> asGeneric(x: T) {}
fun asInterface(timeout: Timeout) {}
fun asNullable(millis: MillisecondsTimeout?) {}

fun main() {
val millis = MillisecondsTimeout(5000)

asInline(millis) // unboxed: used as MillisecondsTimeout itself
asGeneric(millis) // boxed: used as generic type T
asInterface(millis) // boxed: used as type I
asNullable(millis) // boxed: used as MillisecondsTimeout?, which is different from MillisecondsTimeout
}

Inline classes seem to be very similar to type aliases; however, they are not. Both seem to introduce a new type, and both will be represented as the underlying type at runtime. While inline classes introduce a truly new type, type aliases introduce an alternative name (alias) for an existing type.

This functionality is still experimental, and while compiling such code a warning will be reported.

主站蜘蛛池模板: 鄂温| 开远市| 唐山市| 乐平市| 东乌珠穆沁旗| 专栏| 麻城市| 黄浦区| 龙州县| 宁海县| 佛冈县| 台南县| 霍邱县| 寿光市| 大理市| 淳化县| 乌海市| 建德市| 新郑市| 揭西县| 富顺县| 青川县| 阳西县| 泾阳县| 筠连县| 襄樊市| 绍兴市| 宣威市| 西充县| 宜良县| 民勤县| 稻城县| 广饶县| 调兵山市| 哈尔滨市| 潜山县| 大同县| 临西县| 阳城县| 浮山县| 夏河县|