Kotlin 入门笔记06 | 青训营笔记

299 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第19天

泛型

基本用法

一般对于静态语言而言,定义变量时需要指定一个具体的类型(或者通过类型推导判断类型),使用泛型可以在不指定具体类型的情况下进行定义,在实际调用时再指定或者推导,这样能提高代码的可扩展性。

定义泛型类

 class MyClass<T> {
     fun method(param: T): T {
         return param
     }
 }

调用

 val myClass = MyClass<Int>()
 val result = myClass.method(123)

定义泛型方法

 fun <T> method(param: T): T {
     return param
 }

调用(类型推导)

 val myClass = MyClass()
 val result = myClass.method(123)

指定上界

写法

 class MyClass {
     fun <T : Number> method(param: T): T {
         return param
     }
 }

这样 T 就只能是 Number 的子类,比如 Int, Double。

泛型的默认上界是 Any? ,故泛型默认为可空类型。

对 build 函数进行扩展,使其具备 apply 的功能

 fun <T> T.build(block: T.() -> Unit): T {
     block()
     return this
 }

委托

委托是一种设计模式,它的基本理念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。

kotlin 将委托功能分为了两种:类委托和委托属性。

委托模式示例

 class MySet<T>(val helperSet: HashSet<T>) : Set<T> {
     override val size: Int
         get() = helperSet.size
     override fun contains(element: T) = helperSet.contains(element)
     override fun containsAll(elements: Collection<T>) = helperSet.containsAll(elements)
     override fun isEmpty() = helperSet.isEmpty()
     override fun iterator() = helperSet.iterator()
 }

如果只是让大部分的方法实现调用辅助对象中的方法,少部分的方法实现由自己来重写,甚至加入一些自己独有的方法,那么 MySet 就会成为一个全新的数据结构类,这就是委托模式的意义所在。

Kotlin 可以通过 by 关键字来减少委托的模板代码。

 class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet {
     // 自己独有的方法
     fun helloWorld() = println("Hello World")
     // 重写 Set 里 有的方法
     override fun isEmpty() = false
 }

类委托的核心思想是将一个的具体实现委托给另一个类去完成,而委托属性的核心思想是将一个属性(字段)的具体实现委托给另一个类去完成。

示例

 class MyClass {
     var p by Delegate()
 }

这种写法就代表着将p属性的具体实现委托给了 Delegate 类去完成。当调用p属性的时候会自动调用 Delegate 类的 getValue() 方法,当给p属性赋值的时候会自动调用 Delegate 类的 setValue() 方法。

当然 Delegate 类需要有具体的实现。

 class Delegate {
     var propValue: Any? = null
     operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
         return propValue
     }
     operator fun setValue(myClass: MyClass, prop: KProperty<*>, value: Any?) {
         propValue = value
     }
 }

这是一种标准的代码实现模板,在 Delegate 类中我们必须实现 getValue() 和 setValue() 这两个方法,并且都要使用 operator 关键字进行声明。

getValue() 方法要接收两个参数: 第一个参数用于声明该 Delegate 类的委托功能可以在什么 类中使用,这里写成 MyClass 表示仅可在 MyClass 类中使用。 第二个参数 KProperty<*> 是 Kotlin 中的一个属性操作类,可用于获取各种属性相关的值,在当前场景下用不着,但是必须在方法参数上进行声明。另外,<*> 这种泛型的写法表示你不知道或者不关心泛型的具体类型,只是为了通过语法编译而已,有点类似于Java中的写法。至于返回值可以声明成任何类型,根据具体的实现逻辑去写就行了,上述代码只是一种示例写法。

setValue() 方法也是相似的,只不过它要接收3个参数。前两个参数和 getValue() 方法是相同的,最后一个参数表示具体要赋值给委托属性的值,这个参数的类型必须和 getValue() 方法返回值的类型保持一致。

另外如果 属性p 是通过 val 关键字声明的,则不用实现 setValue() 方法