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

Introduction to generics in Kotlin

Generics are a way to specify the relationships between types. Well, that didn't help explain much, did it? Let's try again. Generics are an abstraction of types. Nope, still awful.

We'll try an example, then:

    val listOfStrings = mutableListOf("a", "b", "c") 

Ok, that's easy; we've covered it a lot of times. This code simply creates a list of strings. But what does it actually mean?

Let's try the following line of code:

listOfStrings.add(1) 

This line doesn't compile. That's because the mutableListOf() function uses generics:

public fun <T> mutableListOf(vararg elements: T): MutableList<T> 

Generics create an expectation. No matter which type we use to create our list, from now on we can only put that type in it. It's a great language feature because, on the one hand, we can generalize our data structures or algorithms. No matter what types they hold, they'll still work in exactly the same way.

On the other hand, we still have type safety. The listOfStringsfirst() function is guaranteed to return a String (in this case) and nothing else.

In terms of generics, Kotlin uses an approach that is similar to, but slightly different from, Java. We won't cover all the aspects of generics in this section, but will only provide some guidance to better understand this example. As we go on, we'll encounter more uses of generics.

Let's look at another example.

We'll create a class called Box. Boring, I know:

class Box<T> { 
    private var inside: T? = null 
 
    fun put(t: T) { 
        inside = t 
    }    
    fun get(): T? = inside 
} 

What's great about this box, though, is that by using generics, I can put just about anything in it, for example, a cat:

class Cat 

When I create an instance of a box, I specify what it can hold:

val box = Box<Cat>() 

At compile time, the generics will make sure that it will only hold objects of the correct type:

box.put(Cat()) // This will work 
val cat = box.get() // This will always return a Cat, because that's what our box holds 
box.put("Cat") // This won't work, String is not a Cat 

As you may know, Java uses the wildcards ? extends, and super keywords to specify read-only and write-only types.

Kotlin uses the concepts of in, out, and where.

A type that is marked as in can be used as a parameter but not as a return value. This is also called covariance. In fact, it means that we can return ProducedUnit or something that inherits from it, but not something that is above ProducedUnit in the hierarchy.

Types that are marked as out can be used only as a return value, not as a parameter. This is called contravariance.

Furthermore, we may introduce constraints on types using the where keyword. In our case, we require that the first type implements the Type interface, while the second type implements the Unit interface.

The names of the types themselves, UnitType and ProducedUnit, could be anything we want, T and P, for example. But for the sake of clarity, we'll use more verbose names.

主站蜘蛛池模板: 松潘县| 蚌埠市| 自治县| 山东| 仪征市| 万荣县| 临沧市| 合川市| 清河县| 云和县| 南江县| 民和| 鄂伦春自治旗| 遂川县| 清新县| 德令哈市| 武宁县| 库尔勒市| 霍城县| 家居| 乌兰县| 奎屯市| 吴堡县| 万源市| 即墨市| 卢氏县| 安塞县| 翁源县| 奉新县| 荥经县| 清远市| 响水县| 康保县| 高唐县| 得荣县| 万盛区| 肥乡县| 仪征市| 会理县| 高青县| 卓资县|