overloading - 默认参数与重载,何时使用哪个

标签 overloading kotlin optional-parameters

在 Kotlin 中有两种表达可选参数的方法,一种是指定默认参数值:

fun foo(parameter: Any, option: Boolean = false) { ... }

或者通过引入重载:
fun foo(parameter: Any) = foo(parameter, false)
fun foo(parameter: Any, option: Boolean) { ... }

在哪些情况下首选哪种方式?

这种功能的消费者有什么区别?

最佳答案

在 Kotlin 代码中调用其他 Kotlin 代码可选参数往往是使用重载的规范。使用可选参数应该是您的默认行为。

使用默认值的特殊情况:

  • 作为一般做法或如果不确定 - 使用默认参数而不是覆盖。
  • 如果您希望调用者看到默认值,请使用默认值。它们将显示在 IDE 工具提示(即 Intellij IDEA)中,并让调用者知道它们作为契约(Contract)的一部分被应用。您可以在以下屏幕截图中看到调用 foo()如果 x 的值被省略,将默认一些值和 y :

    enter image description here

    而用函数重载做同样的事情会隐藏这些有用的信息,只会呈现出更加困惑的情况:

    enter image description here
  • 使用默认值会导致两个函数的字节码生成,一个指定所有参数,另一个是桥接函数,可以检查和应用缺失参数及其默认值。不管你有多少默认参数,它总是只有两个功能。因此,在功能总数受限的环境(即 Android)中,最好只拥有这两个功能,而不是完成相同工作所需的大量重载。

  • 您可能不想使用默认参数值的情况:
  • 当您希望另一种 JVM 语言能够使用默认值时,您需要使用显式重载或使用 @JvmOverloads annotation哪一个:

    For every parameter with a default value, this will generate one additional overload, which has this parameter and all parameters to the right of it in the parameter list removed.

  • 您有一个以前版本的库,并且为了二进制 API 兼容性,添加默认参数可能会破坏现有编译代码的兼容性,而添加重载则不会。
  • 您有一个以前的现有功能:
    fun foo() = ...
    

    并且您需要保留该函数签名,但您还想添加另一个具有相同签名但附加可选参数的函数:
    fun foo() = ...
    fun foo(x: Int = 5) = ...   // never can be called using default value
    

    您将无法在第二个版本中使用默认值(除了通过反射 callBy )。取而代之的是所有 foo()不带参数的调用仍然调用函数的第一个版本。所以你需要使用没有默认值的不同重载,否则你会混淆函数的用户:
    fun foo() = ...  
    fun foo(x: Int) = ...
    
  • 您将参数放在一起可能没有意义,因此重载允许您将参数分组为有意义的协调集。
  • 使用默认值调用方法必须执行另一个步骤来检查缺少哪些值并应用默认值,然后将调用转发到真正的方法。因此,在性能受限的环境(即 Android、嵌入式、实时、方法调用上的十亿次循环迭代)中,可能不需要这种额外的检查。虽然如果您在分析中没有看到问题,这可能是一个虚构的问题,可能由 JVM 内联,并且可能根本没有任何影响。在担心之前先测量一下。

  • 不真正支持任何一种情况的情况:

    如果您正在阅读其他语言中关于此的一般论点...
  • C# answer for this similar question受人尊敬的 Jon Skeet 提到,如果默认值可以在构建之间更改,那么您应该小心使用默认值,这将是一个问题。在 C# 中,默认值位于调用站点,而在 Kotlin 中,对于非内联函数,它位于被调用的(桥)函数内部。因此,对于 Kotlin 而言,更改隐藏和显式默认值的影响是相同的,并且此论点不应影响决策。
  • 同样在 C# 回答中说,如果团队成员对使用默认参数有相反的看法,那么也许不要使用它们。这不应该应用于 Kotlin,因为它们是核心语言功能,并且自 1.0 之前就在标准库中使用,并且不支持限制它们的使用。对方团队成员应默认使用默认参数,除非他们有明确的案例使它们无法使用。而在 C# 中,它是在该语言的生命周期后期引入的,因此具有更多“可选采用”的感觉
  • 关于overloading - 默认参数与重载,何时使用哪个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39733830/

    相关文章:

    关于继承和转换的 C++ 问题

    c++ - C++中标准库函数的函数重载

    r - 当内部函数参数依赖于可选参数时,R 中的参数传递

    c++ - 运算符过载但不可行

    c++ - 在 C++ 中重载运算符时指定 "const"

    java - 让 Hibernate 创建 TIMESTAMP 列

    java - 没有提供数组访问的get方法-向矩阵分配新值时出错

    android - 无法解析 com.squareup.sqldelight :runtime:1. 1.3

    tsql - 如何在 T-SQL 存储过程中使用可选参数?

    ios - 如何在 Swift 协议(protocol)中定义可选方法?