轻松掌握 Kotlin 泛型:形参与实参
2023-12-26 08:09:15
Kotlin中的形参和实参:掌握泛型的关键
什么是泛型?
泛型是编程语言中的一种特性,允许您编写代码,该代码可以在多种类型上运行,而无需显式指定类型。它提高了代码的可重用性和灵活性。
形参和实参
在泛型编程中,形参就像占位符,表示泛型类型。它们在函数或类定义中使用尖括号表示,例如 <T>
。实参是指定泛型类型实际类型的具体类型。
协变和逆变
协变和逆变了形参和实参之间的关系。
- 协变形参(out) :形参可以是实参的子类。这意味着您可以将子类作为实参传递给父类形参。例如,
out List<Animal>
可以接受List<Dog>
,因为Dog
是Animal
的子类。 - 逆变形参(in) :形参可以是实参的父类。这意味着您可以将父类作为实参传递给子类形参。例如,
in Animal
可以接受Dog
,因为Dog
是Animal
的子类。
不变形参
如果形参既不是协变也不是逆变,则称为不变形参。不变形参必须与实参类型完全匹配。例如,List<Animal>
只能接受 List<Animal>
,不能接受 List<Dog>
或 List<Object>
。
星投影
星投影(*)是一种特殊形式的形参,表示任何类型。它允许泛型方法或类处理不同类型的对象。例如,List<*>
可以接受任何类型的列表,无论元素类型如何。
示例
以下是形参和实参如何协同工作的示例:
class Animal(val name: String)
class Dog(name: String) : Animal(name)
class Cat(name: String) : Animal(name)
fun printAnimalNames(animals: List<Animal>) {
for (animal in animals) {
println(animal.name)
}
}
val dogList: List<Dog> = listOf(Dog("Buddy"), Dog("Max"))
val catList: List<Cat> = listOf(Cat("Kitty"), Cat("Fluffy"))
printAnimalNames(dogList) // 编译通过
printAnimalNames(catList) // 编译通过
在上面示例中,printAnimalNames()
函数接受 List<Animal>
类型的参数。dogList
和 catList
都是 Animal
的子类,因此函数可以接受它们作为实参。
结论
理解形参和实参的概念对于编写使用 Kotlin 泛型的安全和可维护的代码至关重要。掌握这些概念将使您能够编写出色的代码,提高可重用性并减少错误。
常见问题解答
1. 如何判断形参是协变还是逆变?
查看形参声明前是否带有 out
或 in
。out
表示协变,in
表示逆变。
2. 为什么不变形参很重要?
不变形参确保类型安全。它防止您将错误类型的对象传递给泛型方法或类。
3. 星投影有什么好处?
星投影允许您编写处理不同类型对象的通用代码。它提高了代码的可重用性。
4. 如何在 Kotlin 中编写协变或逆变函数?
使用 out
或 in
关键字指定形参的协变性或逆变性。例如:
fun printAnimalNames(animals: out List<Animal>) {
// ...
}
5. 编写使用泛型的代码时应注意哪些事项?
- 确保使用正确的协变性或逆变性。
- 避免使用不变形参,除非绝对必要。
- 考虑使用星投影提高代码的可重用性。
- 编写单元测试以验证泛型代码的正确性。