使用内联函数 kotlin

Using inline function kotlin

我知道 kotlin 主页上有文档,但没有明确说明何时使用它,为什么这个函数需要一个接收器作为一个函数。创建内联函数的正确定义的正确方法是什么。

  1. 这是内联函数
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY, block: (date: String) -> String): String {
    return try {
        var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
        val date = sdf.parse(this.orEmpty())
        sdf = SimpleDateFormat(outputDate, Locale.US)
        block(sdf.format(date ?: Date()).orEmpty())
    } catch (ex: Exception) {
        block("")
    }
}

  1. 我们也可以这样做
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY): String {
    return try {
        var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
        val date = sdf.parse(this.orEmpty())
        sdf = SimpleDateFormat(outputDate, Locale.US)
        sdf.format(date ?: Date()).orEmpty()
    } catch (ex: Exception) {
        ""
    }
}

谁能详细解释一下?

编辑:

我知道内联函数会在编译器调用时插入代码。但这引起了我的注意,当我想使用没有功能参数接收器的内联函数时,警告显示为 this 在其中应该有更好的解释。我也想明白为什么会有这样的推荐。

这里东西很少。

首先,您询问有关将函数与接收器一起使用的问题。在这两种情况下,接收者都是 String?.toDateString()String? 部分。这意味着您可以调用函数 就好像 它是 String 的一个方法,例如"2021-01-15 12:00:00".toDateString(…).

原来的String?在函数中可以作为this访问;您可以在 sdf.parse(this.orEmpty()) 调用中看到它。 (它并不总是像这样明显;您可以简单地调用 sdf.parse(orEmpty()),其中隐含 this.。)

然后你问inline functions。您所要做的就是将函数标记为inline,编译器将自动在调用它的任何地方插入它的代码,而不是按照通常的方式定义一个函数。但是您不必担心它是如何实现的;代码中只有一些可见的效果。特别是,如果一个函数是内联的并且接受一个函数参数,那么它的 lambda 可以做一些它不能做的事情(比如调用 return)。

这引出了我认为是您真正的问题:关于 block 函数参数。您的第一个示例具有此参数,类型为 (date: String) -> String — 即函数采用单个 String 参数并返回另一个 String。 (这个的技术术语是 toDateString() 是一个 higher-order function。)

toDateString() 函数在返回之前调用此 block 函数,将其应用于已格式化的日期字符串,然后再将其返回给调用者。

至于为什么会这样,很难说。这就是我们将文档注释放在函数之前的原因:解释代码中不明显的任何内容!理想情况下,会有注释解释为什么您需要提供 block lamdba(或函数引用),而它对函数的作用并不重要。

有时候以这种方式传递的方块非常有用。例如,joinToString() 函数接受一个可选的 transform 参数,它在将每个项目加入列表之前将其应用于每个项目。如果不这样做,效果将很难获得。 (在调用 joinToString() 之前,您可能必须将 map() 应用于集合,这会降低效率。)

但这不是那些时代之一。正如你的第二个例子所示,toDateString() 在没有 block 参数的情况下也能很好地工作——然后如果你需要通过另一个函数传递结果,你可以在 toDateString() 上调用它结果。

也许如果您在看到此内容的“kotlin 主页面”中包含一个 link,它可能会提供更多上下文?


编辑后的问题还询问了 IDE 警告。当它认为内联函数不会带来显着改进时,就会显示出来。

当不涉及 lambda 时,内联函数的唯一潜在好处是性能,这是一种权衡。它 可能 避免在任何地方调用函数调用的开销 — 但 Java 运行时通常会自行内联小函数。让编译器进行内联是以在调用函数的任何地方复制函数代码为代价的;增加的代码大小不太可能适合内存缓存,也不太可能被 Java 运行时优化——因此最终会降低整体性能。因为这并不总是很明显,所以 IDE 给出了警告。

不过,当涉及到 lambda 时,情况就不同了。在这种情况下,内联会影响功能:例如,它允许 non-local returns and reified type parameters。因此,在这种情况下,有充分的理由使用 inline 而不管任何性能影响,并且 IDE 不会发出警告。

(事实上,如果一个函数调用它传递的 lambda,内联可以有更显着的性能优势:不仅函数本身被内联,而且 lambda 本身通常也是如此,删除两级函数调用 — 而且 lambda 经常被重复调用,所以可以真正节省。)