使用 where 的泛型函数与类型约束
编写带有单个或多个类型约束的泛型函数。
使用 where 的泛型函数与类型约束 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。
泛型函数基础
泛型函数会在函数名称前的尖括号中声明类型参数。类型参数可以用于参数类型和返回类型。
fun <T> identity(value: T): T = value
fun <T> listOf2(a: T, b: T): List<T> = listOf(a, b)
fun main() {
println(identity(42)) // 42
println(identity("hello")) // hello
println(listOf2(1, 2)) // [1, 2]
}使用 : 约束上界
使用 : 为类型参数指定上界。该类型必须是上界的子类型。
fun <T : Comparable<T>> max(a: T, b: T): T = if (a >= b) a else b
fun main() {
println(max(3, 7)) // 7
println(max("apple", "banana")) // banana
// max(listOf(1), listOf(2)) // error: List is not Comparable
}可空上界
默认上界是可空的 Any?。使用 T : Any 可以排除 null。
fun <T : Any> notNull(value: T?): T {
return value ?: throw IllegalArgumentException("Value is null")
}
fun main() {
println(notNull("hello")) // hello
try { notNull(null) } catch (e: Exception) { println(e.message) }
}使用 where 添加多重约束
使用 where 子句为单个类型参数应用多个约束。
fun <T> process(item: T): String
where T : Comparable<T>, T : CharSequence {
return "Length=${item.length}, sorted=${item > "a"}"
}
fun main() {
println(process("kotlin")) // Length=6, sorted=true
// process(42) // error: Int doesn't implement CharSequence
}类上的 where
where 子句同样适用于类级别的类型参数。
class SortedContainer<T>(private val items: MutableList<T> = mutableListOf())
where T : Comparable<T>, T : Any {
fun add(item: T) { items.add(item); items.sort() }
fun top(): T? = items.lastOrNull()
}
fun main() {
val c = SortedContainer<Int>()
c.add(5); c.add(2); c.add(8)
println(c.top()) // 8
}泛型扩展函数
扩展函数也可以拥有类型参数,因此能够用于特定的泛型类型。
fun <T : Comparable<T>> List<T>.second(): T? {
return if (size >= 2) this[1] else null
}
fun main() {
println(listOf(10, 20, 30).second()) // 20
println(listOf("a").second()) // null
}返回位置中的类型参数
泛型函数可以根据上下文推断类型,从而无需在调用位置显式指定类型参数。
fun <T> MutableList<T>.popOrDefault(default: T): T {
return if (isEmpty()) default else removeAt(lastIndex)
}
fun main() {
val list = mutableListOf(1, 2, 3)
println(list.popOrDefault(0)) // 3
println(list.popOrDefault(0)) // 2
println(mutableListOf<Int>().popOrDefault(-1)) // -1
}可复用的泛型工具
泛型函数可以让工具函数适用于多种类型,而无需重复编写代码。
fun <T> Iterable<T>.firstOrElse(default: T): T = firstOrNull() ?: default
fun <T, R : Comparable<R>> Iterable<T>.maxByOrElse(selector: (T) -> R, default: T): T =
maxByOrNull(selector) ?: default
fun main() {
println(listOf<String>().firstOrElse("fallback")) // fallback
println(listOf("a","bbb","cc").maxByOrElse({ it.length }, "")) // bbb
}星号投影与有界通配符
请对比有界类型参数和星号投影:当您需要生成或消费 T 时,有界类型参数很有用;当类型未知时,则应使用星号投影。
fun <T : Number> sumList(list: List<T>): Double =
list.sumOf { it.toDouble() }
// Star projection: read-only, type unknown
fun printAll(list: List<*>) = list.forEach { println(it) }
fun main() {
println(sumList(listOf(1, 2, 3))) // 6.0
printAll(listOf("a", 1, true)) // a, 1, true
}泛型二元组交换
这是一个简单但很有说明性的泛型函数,用于反转二元组的两个组成部分。
fun <A, B> Pair<A, B>.swap(): Pair<B, A> = Pair(second, first)
fun main() {
val pair = Pair("hello", 42)
val swapped = pair.swap()
println(swapped) // (42, hello)
}实践:泛型结果解包器
使用有界泛型编写一个工具,通过带类型的转换函数映射 Result<T>。
fun <T : Any, R : Any> Result<T>.mapNotNull(transform: (T) -> R?): Result<R> {
return fold(
onSuccess = { v ->
val r = transform(v)
if (r != null) Result.success(r) else Result.failure(NoSuchElementException())
},
onFailure = { Result.failure(it) }
)
}
fun main() {
val r = Result.success("123")
val n = r.mapNotNull { it.toIntOrNull() }
println(n) // Success(123)
}快速检查
如何为一个类型参数应用多个约束?
回顾
泛型函数使用类型参数编写可复用且类型安全的代码。使用 : 指定单个上界,使用 where 指定多个上界。Kotlin 编译器会在调用位置强制执行这些约束。
常见问题解答
「使用 where 的泛型函数与类型约束」课时是免费的吗?
是的 — 「使用 where 的泛型函数与类型约束」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。
「使用 where 的泛型函数与类型约束」这节课中我会学到什么?
编写带有单个或多个类型约束的泛型函数。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Kotlin Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 where 的泛型函数与类型约束」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Kotlin Academy 课中编写并运行代码吗?
能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 where 的泛型函数与类型约束
- 声明处型变:in 与 out
- 星号投影与 * 的使用时机
- 类型擦除与 reified 类型参数