kotlin 泛型基础

发布时间 2023-11-16 09:11:53作者: LCAC

一、泛型函数

如下是泛型函数的一种构造

在fun函数标记的右边增加该函数要使用的类型形参

fun <T> List<T>.slice(indices: IntArray): List<T> {
    val ret = mutableListOf<T>()
    for (v in indices) {
        ret.add(this[v])
    }
    return ret
}

listOf(3,4,5,6,7,8,1,2).slice(intArrayOf(4,5,3,2))

如上在调用slice之后,返回了一个新的List并且对应的类型为T

上述的调用也可以为:listOf<Int>(3,4,5,6,7,8,1,2).slice<Int>(intArrayOf(4,5,3,2))

这里listOf<Int>对应的List<T>, slice<Int>对应的fun <T> ;

但是为何实际不需要添加<Int>呢?是因为kotlin能够进行推理得到对应的类型!

 

二、泛型的扩展属性

这里强调扩展属性,是因为普通属性不能拥有类型参数,不能在一个类的属性中存储多个不同类型的值。例如:val <T> x: T = TODO()

如下是泛型的扩展属性的一个例子,返回列表的倒数第二个参数

val <T> List<T>.penultimate: T
get() = this[size - 2]

listOf(1,2,3,4).penultimate

 

三、泛型类

语法是:在类名称后加上一对尖括号,并把类型参数放在尖括号内来声明泛型类和接口。

interface Compareable<T> { // 这里声明一个接口,并且在该接口中声明了类型参数
    fun compareTo(other: T): Int
}

class String1(val value: String): Compareable<String1> { // 在实现的时候需要指明接口具体要具现的类型,这里可以使用类本身作为具现类
    override fun compareTo(other: String1): Int {
        return this.value.length - other.value.length
    }
}

    val string1 = String1("kk")
    println(string1.compareTo(String1("qqq")))

 

四、类型参数的约束

类型参数的约束可以限制泛型类和函数的类型实参的类型

指定泛型类型形参的上界即泛型类型必须为上界类型的子类型

如下是对应的例子

fun <T: Number> List<T>.sum(): Int { // 这里指定了上界是Number
    var ret = 0
    this.forEach { ret += it.toInt() } // 因为T 是Number或者Number的子类,所以这里可以调用toInt()
    return ret
}

listOf(1,2,3).sum()

 

2、带类型参数约束的函数

fun <T: Comparable<T>> max(first: T, second: T): T { // T 必须是一个可比较的类型
    return if (first > second) first else second
}

max("kk", "qqq")

 

3、如果要对T指定多个约束的话,则需要使用where关键字,多个约束的中间用逗号隔开,并且写在函数的最后面

fun <T> ensuretrail(seq: T): T where T: CharSequence, T: Appendable { // 这里返回的类型为T
if (!seq.endsWith('.')) {
seq.append('.')
}

return seq
}

 

4、当没有类型参数的约束时候,它的默认约束是Any? , 此时T是可空的类型,如果要让T非空则需要明确指定非空的类型