重载
在没有默认参数支持的语言中,通常使用重载来模拟该功能。
术语重载是指函数的名称:您可以使用相同的名称(为该名称重载)来表示不同的函数,只要参数列表不同即可。以下是对成员函数 f()
进行重载的示例:
// Overloading/Overloading.kt
package overloading
import atomictest.eq
class Overloading {
fun f() = 0
fun f(n: Int) = n + 2
}
fun main() {
val o = Overloading()
o.f() eq 0
o.f(11) eq 13
}
在 Overloading
类中,我们看到两个具有相同名称 f()
的函数。函数的签名由名称、参数列表和返回类型组成。Kotlin 通过比较签名来区分不同的函数。在重载函数时,参数列表必须是唯一的,不能根据返回类型进行重载。
上述调用表明它们确实是不同的函数。函数签名还包括关于封闭类的信息(或者如果它是扩展函数,则是接收者类型)。
请注意,如果类已经有一个与扩展函数具有相同签名的成员函数,则 Kotlin 会优先选择成员函数。但是,您可以使用扩展函数重载成员函数:
// Overloading/MemberVsExtension.kt
package overloading
import atomictest.eq
class My {
fun foo() = 0
}
fun My.foo() = 1 // [1]
fun My.foo(i: Int) = i + 2 // [2]
fun main() {
My().foo() eq 0
My().foo(1) eq 3
}
- [1] 声明重复成员函数的扩展是没有意义的,因为它永远不会被调用。
- [2] 您可以使用扩展函数通过提供不同的参数列表来重载成员函数。
不要使用重载来模拟默认参数。也就是说,不要这样做:
// Overloading/WithoutDefaultArguments.kt
package withoutdefaultarguments
import atomictest.eq
fun f(n: Int) = n + 373
fun f() = f(0)
fun main() {
f() eq 373
}
没有参数的函数只是调用了第一个函数。通过使用默认参数,这两个函数可以被一个函数替代:
// Overloading/WithDefaultArguments.kt
package withdefaultarguments
import atomictest.eq
fun f(n: Int = 0) = n + 373
fun main() {
f() eq 373
}
在这两个示例中,您可以在没有参数的情况下调用函数,或者通过传递整数值来调用函数。更推荐使用 WithDefaultArguments.kt
中的形式。
在使用重载函数和默认参数时,调用重载函数会搜索“最近”的匹配项。在下面的示例中,`
main()中的
foo()` 调用不会调用带有默认参数 99 的函数的第一个版本,而是调用第二个版本,即没有参数的版本:
// Overloading/OverloadedVsDefaultArg.kt
package overloadingvsdefaultargs
import atomictest.*
fun foo(n: Int = 99) = trace("foo-1-$n")
fun foo() {
trace("foo-2")
foo(14)
}
fun main() {
foo()
trace eq """
foo-2
foo-1-14
"""
}
您永远无法使用默认参数 99,因为 foo()
总是调用 f()
的第二个版本。
为什么重载有用?它允许您更清楚地表达“同一主题的变化”,而不是被迫使用不同的函数名称。假设您想要添加函数:
// Overloading/OverloadingAdd.kt
package overloading
import atomictest.eq
fun addInt(i: Int, j: Int) = i + j
fun addDouble(i: Double, j: Double) = i + j
fun add(i: Int, j: Int) = i + j
fun add(i: Double, j: Double) = i + j
fun main() {
addInt(5, 6) eq add(5, 6)
addDouble(56.23, 44.77) eq
add(56.23, 44.77)
}
addInt()
接受两个 Int
,返回一个 Int
,而 addDouble()
接受两个 Double
,返回一个 Double
。如果没有重载,您无法将操作命名为 add()
,因此程序员通常将 what 与 how 混为一谈,以生成唯一的名称(您也可以使用随机字符创建唯一的名称,但是通常的模式是使用参数类型等有意义的信息)。相比之下,重载的 add()
更清晰。
在语言中缺少重载并不是一个严重的困扰,但这个特性提供了宝贵的简化,产生了更可读的代码。使用重载时,您只需要说出 what,这提高了抽象级别,减轻了读者的思维负担。如果您想了解 how,可以查看参数。请注意,重载减少了冗余:如果我们必须说
addInt()
和addDouble()
,那么实际上在函数名称中重复了参数信息。
练习和解答可以在 www.AtomicKotlin.com 上找到。