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

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.

主站蜘蛛池模板: 霞浦县| 珲春市| 化州市| 弥渡县| 长沙县| 东辽县| 二连浩特市| 德兴市| 临西县| 赫章县| 郸城县| 南涧| 弋阳县| 彭州市| 赤峰市| 衡阳县| 军事| 嘉定区| 曲靖市| 泗洪县| 长武县| 房山区| 新田县| 佛学| 平阳县| 柘荣县| 公主岭市| 浑源县| 盖州市| 阿拉善左旗| 瑞金市| 上思县| 惠来县| 惠州市| 乌兰察布市| 合江县| 铁岭市| 汕尾市| 溆浦县| 中超| 息烽县|