- Hands-On Design Patterns with Kotlin
- Alexey Soshin
- 554字
- 2021-06-25 20:49:29
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 listOfStrings. first() 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.
- 數字媒體應用教程
- Building Mobile Applications Using Kendo UI Mobile and ASP.NET Web API
- Symfony2 Essentials
- C++面向對象程序設計習題解答與上機指導(第三版)
- Extending Puppet(Second Edition)
- IoT Projects with Bluetooth Low Energy
- C陷阱與缺陷
- 監控的藝術:云原生時代的監控框架
- Flask Web開發:基于Python的Web應用開發實戰(第2版)
- 超簡單:用Python讓Excel飛起來(實戰150例)
- Python預測之美:數據分析與算法實戰(雙色)
- Azure for Architects
- Internet of Things with Arduino Cookbook
- Selenium Essentials
- Access 2010數據庫教程(微課版)