kotlin - 什么时候应该更喜欢 Kotlin 扩展函数?

在 Kotlin 中,具有至少一个参数的函数可以定义为常规非成员函数或 extension function一个参数是接收者。

至于作用域,似乎没有区别:两者都可以在类和其他函数内部或外部声明,并且两者都可以或不能具有同等的可见性修饰符。

语言引用似乎不建议针对不同情况使用常规函数或扩展函数。

所以,我的问题是:什么时候扩展函数比普通的非成员函数更有优势?什么时候普通函数优于扩展?

foo.bar(baz, baq) vs bar(foo, baz, baq).

这只是函数语义的暗示(接收器绝对是焦点)还是存在使用扩展函数使代码更清晰或开辟机会的情况?

最佳答案

扩展函数在少数情况下很有用,而在其他情况下则是强制性的:

惯用案例:

  1. 当您想要增强、扩展或更改现有 API 时。扩展函数是通过添加新功能来更改类的惯用方式。您可以添加extension functions和 extension properties .参见 Jackson-Kotlin Module 中的示例用于向 ObjectMapper 类添加方法,以简化 TypeReference 和泛型的处理。

  2. 为无法在 null 上调用的新方法或现有方法添加 null 安全性。例如,String?.isNullOrBlank() 的 String 的扩展函数允许您甚至在 null 字符串上使用该函数,而无需自己执行 null 首先检查。函数本身在调用内部函数之前进行检查。见 documentation for extensions with Nullable Receiver

强制案例:

  1. 当你想要一个接口(interface)的内联默认函数时,你必须使用扩展函数将它添加到接口(interface),因为你不能在接口(interface)声明中这样做(内联函数必须是 final 目前在界面中是不允许的)。这在您需要内联具体化函数时很有用,for example this code from Injekt

  2. 当您想将 for (item in collection) { ... } 支持添加到当前不支持该用法的类时。您可以添加一个遵循 for loops documentation 中描述的规则的 iterator() 扩展方法。 -- 即使返回的类似迭代器的对象也可以使用扩展来满足提供 next()hasNext() 的规则。

  3. 将运算符添加到现有的类,例如 +* (#1 的特殊化,但您不能以任何其他方式执行此操作,因此是强制性的)。见 documentation for operator overloading

可选案例:

  1. 您想控制调用者何时可以看到某些内容的范围,因此您只能在允许调用可见的上下文中扩展类。这是可选的,因为您可以只允许始终看到扩展名。 see answer in other SO question for scoping extension functions

  2. 你有一个接口(interface),你想简化所需的实现,同时仍然允许用户使用更简单的帮助函数。您可以选择为接口(interface)添加默认方法以提供帮助,或者使用扩展函数来添加接口(interface)的非预期实现部分。一种允许覆盖默认值,另一种则不允许(扩展与成员的优先级除外)。

  3. 当您想将功能与功能类别相关联时;扩展函数使用它们的接收器类作为找到它们的地方。它们的 namespace 成为可以触发它们的类(或多个类)。而顶级函数将更难找到,并且会填满 IDE 代码完成对话框中的全局 namespace 。您还可以修复现有的库 namespace 问题。例如,在 Java 7 中,您有 Path 类,并且很难找到 Files.exist(path) 方法,因为它的名称间隔很奇怪。该函数可以直接放在 Path.exists() 上。 (@kirill)

优先规则:

在扩展现有类时,请牢记优先规则。它们在 KT-10806 中进行了描述如:

For each implicit receiver on current context we try members, then local extension functions(also parameters which have extension function type), then non-local extensions.

https://stackoverflow.com/questions/35317940/

相关文章:

constructor - 如何在 Kotlin 中扩展具有多个构造函数的类?

android - 在当前主题中找不到样式 'cardView Style'

java - 在 Kotlin 中定义 log TAG 常量的最佳方法是什么?

kotlin - 在 Android Studio 中构建时如何解决错误 "Failed to re

android - 如何在 Android 上使用 Kotlin 显示 Toast?

java - 在 Kotlin 中同时扩展和实现

dictionary - Kotlin 是否有 Map 文字的语法?

kotlin - Kotlin 中的 crossinline 和 noinline 有什么区别?

spring - 如何在基于 Spring 的强类型语言中正确执行 PATCH - 示例

generics - kotlin 中的 out 关键字是什么