在 Kotlin 中,至少有一个参数的函数可以定义为常规非成员函数或定义为扩展功能 https://kotlinlang.org/docs/reference/extensions.html#extension-functions其中一个参数是接收者。
至于作用域,似乎没有什么区别:两者都可以在类和其他函数的内部或外部声明,并且都可以或不可以同等地具有可见性修饰符。
语言参考似乎不建议在不同情况下使用常规函数或扩展函数。
所以,我的问题是:扩展函数什么时候比常规非成员函数更有优势?当常规的超过扩展时?
foo.bar(baz, baq)
vs bar(foo, baz, baq)
.
它只是函数语义的暗示(接收者肯定是焦点)还是在某些情况下使用扩展函数使代码更加简洁或开辟了机会?
扩展函数在某些情况下很有用,但在其他情况下是必需的:
惯用案例:
-
当您想要增强、扩展或更改现有 API 时。扩展函数是通过添加新功能来更改类的惯用方法。你可以加扩展功能 https://kotlinlang.org/docs/reference/extensions.html#extension-functions and 扩展属性 https://kotlinlang.org/docs/reference/extensions.html#extension-properties。请参阅中的示例Jackson-Kotlin 模块 https://github.com/FasterXML/jackson-module-kotlin/blob/master/src/main/kotlin/com/fasterxml/jackson/module/kotlin/Extensions.kt#L15-L32用于添加方法到ObjectMapper
类简化了处理TypeReference
和仿制药。
-
向无法调用的新方法或现有方法添加空安全性null
。例如 String of 的扩展函数String?.isNullOrBlank()
允许您甚至在null
字符串而不必自己做null
先检查一下。该函数本身在调用内部函数之前进行检查。看Nullable Receiver 扩展的文档 https://kotlinlang.org/docs/reference/extensions.html#nullable-receiver
强制案例:
-
当您想要接口的内联默认函数时,必须使用扩展函数将其添加到接口中,因为您不能在接口声明中执行此操作(内联函数必须是final
目前接口中不允许这样做)。当您需要内联具体化函数时,这很有用,例如来自 Injekt 的这段代码 https://github.com/kohesive/injekt/blob/master/api/src/main/kotlin/uy/kohesive/injekt/api/Registry.kt#L5-L49
-
当你想添加时for (item in collection) { ... }
支持当前不支持该用法的类。您可以添加一个iterator()
遵循中描述的规则的扩展方法for 循环文档 https://kotlinlang.org/docs/reference/control-flow.html#for-loops-- 即使返回的类似迭代器的对象也可以使用扩展来满足提供的规则next()
and hasNext()
.
-
将运算符添加到现有类中,例如+
and *
(#1 的专业化,但你不能以任何其他方式做到这一点,所以是强制性的)。看运算符重载的文档 https://kotlinlang.org/docs/reference/operator-overloading.html
可选案例:
-
您希望控制某些内容对调用者可见的范围,因此您仅在允许调用可见的上下文中扩展该类。这是可选的,因为您可以允许扩展始终可见。请参阅其他 SO 问题的答案以了解扩展函数的范围 https://stackoverflow.com/a/34797367/3679676
-
您有一个界面,您希望简化所需的实现,同时仍然为用户提供更简单的帮助函数。您可以选择为接口添加默认方法来提供帮助,或者使用扩展函数来添加接口中非预期实现的部分。一种允许覆盖默认值,另一种则不允许(扩展与成员的优先级除外)。
-
当您想要将功能与功能类别相关联时;扩展函数使用它们的接收器类作为查找它们的位置。它们的名称空间成为可以触发它们的类(或多个类)。而顶级函数将更难找到,并且会填满 IDE 代码完成对话框中的全局名称空间。您还可以修复现有的库名称空间问题。例如,在 Java 7 中,您有Path
类并且很难找到Files.exist(path)
方法,因为它的名称间隔很奇怪。该函数可以直接放在Path.exists()
反而。 (@基里尔)
优先规则:
扩展现有类时,请记住优先级规则。它们的描述见KT-10806 https://youtrack.jetbrains.com/issue/KT-10806#comment=27-1283497 as:
对于当前上下文中的每个隐式接收器,我们尝试成员,然后是本地扩展函数(也是具有扩展函数类型的参数),然后是非本地扩展。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)