【问题标题】:Using inline function kotlin使用内联函数 kotlin
【发布时间】:2021-01-15 11:00:50
【问题描述】:

我知道在 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 应该有更好的解释。我也想了解为什么会有这样的建议。

【问题讨论】:

    标签: kotlin inline


    【解决方案1】:

    这里的东西很少。

    首先,您询问如何将函数与接收器一起使用。在这两种情况下,接收者都是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 函数,将其应用于已格式化的日期字符串,然后再将其返回给调用者。

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

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

    但这不是那个时代之一。正如您的第二个示例所示,toDateString() 可以在没有 block 参数的情况下完美运行 - 然后如果您需要通过另一个函数传递结果,您可以在 toDateString() 的结果上调用它。

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


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

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

    但是,当涉及 lambda 时,情况就不同了。在这种情况下,内联会影响功能:例如,它允许non-local returnsreified type parameters。因此,在这种情况下,使用inline 是有充分理由的,无论性能影响如何,IDE 也不会发出警告。

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

    【讨论】:

    • 感谢您的精彩解释,我已经添加了有关引起注意的问题的更多详细信息。
    猜你喜欢
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    相关资源
    最近更新 更多