什么时候应该更喜欢 Kotlin 扩展函数? [英] When should one prefer Kotlin extension functions?

查看:25
本文介绍了什么时候应该更喜欢 Kotlin 扩展函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Kotlin 中,具有至少一个参数的函数可以定义为常规非成员函数或 扩展函数,其中一个参数是接收器.

In Kotlin, a function with at least one argument can be defined either as a regular non-member function or as an extension function with one argument being a receiver.

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

As to the scoping, there seems to be no difference: both can be declared inside or outside classes and other functions, and both can or cannot have visibility modifiers equally.

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

Language reference seems not to recommend using regular functions or extension functions for different situations.

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

So, my question is: when do extension functions give advantage over regular non-member ones? And when regular ones over extensions?

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

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

Is it just a hint of a function semantics (receiver is definitely in focus) or are there cases when using extensions functions makes code much cleaner or opens up opportunities?

推荐答案

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

Extension functions are useful in a few cases, and mandatory in others:

惯用案例:

  1. 当您想要增强、扩展或更改现有 API 时.扩展函数是通过添加新功能来更改类的惯用方法.您可以添加扩展功能扩展属性.请参阅 Jackson-Kotlin 模块,用于向 ObjectMapper 类添加方法,以简化 TypeReference 和泛型的处理.

  1. When you want to enhance, extend or change an existing API. An extension function is the idiomatic way to change a class by adding new functionality. You can add extension functions and extension properties. See an example in the Jackson-Kotlin Module for adding methods to the ObjectMapper class simplifying the handling of TypeReference and generics.

为无法在 null 上调用的新方法或现有方法添加空安全.例如,String of String?.isNullOrBlank() 的扩展函数允许您甚至在 null 字符串上使用该函数,而无需自己执行 null 首先检查.函数本身会在调用内部函数之前进行检查.请参阅有关可空接收器扩展的文档

Adding null safety to new or existing methods that cannot be called on a null. For example the extension function for String of String?.isNullOrBlank() allows you to use that function even on a null String without having to do your own null check first. The function itself does the check before calling internal functions. See documentation for extensions with Nullable Receiver

强制性案例:

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

  1. When you want an inline default function for an interface, you must use an extension function to add it to the interface because you cannot do so within the interface declaration (inlined functions must be final which is not currently allowed within an interface). This is useful when you need inline reified functions, for example this code from Injekt

当您想将 for (item in collection) { ... } 支持添加到当前不支持该用法的类时.您可以添加遵循 iterator() 扩展方法rel="noreferrer">for 循环文档 -- 即使返回的类似迭代器的对象也可以使用扩展来满足提供 next()hasNext().

When you want to add for (item in collection) { ... } support to a class that does not currently support that usage. You can add an iterator() extension method that follows the rules described in the for loops documentation -- even the returned iterator-like object can use extensions to satisfy the rules of providing next() and hasNext().

向现有类添加运算符,例如 +*(#1 的特化,但您不能以任何其他方式执行此操作,因此是强制性的).请参阅操作符重载文档

Adding operators to existing classes such as + and * (specialization of #1 but you can't do this in any other way, so is mandatory). See documentation for operator overloading

可选案例:

  1. 您希望控制调用者何时可以看到某些内容的范围,因此您仅在允许调用可见的上下文中扩展该类.这是可选的,因为您可以只允许始终看到扩展.请参阅其他 SO 问题中的答案以了解范围扩展功能

您有一个界面,您希望简化所需的实现,同时仍为用户提供更简单的辅助功能.您可以选择为接口添加默认方法以提供帮助,或使用扩展函数添加接口的非预期实现部分.一个允许覆盖默认值,另一个不允许(除了扩展与成员的优先级).

You have an interface that you want to simplify the required implementation, while still allowing more easy helper functions for the user. You can optionally add default methods for the interface to help, or use extension functions to add the non-expected-to-be-implemented parts of the interface. One allows overriding of the defaults, the other does not (except for precedence of extensions vs. members).

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

When you want to relate functions to a category of functionality; extension functions use their receiver class as a place from which to find them. Their name space becomes the class (or classes) from which they can be triggered. Whereas top-level functions will be harder to find, and will fill up the global name space in IDE code completion dialogs. You can also fix existing library name space issues. For example, in Java 7 you have the Path class and it is difficult to find the Files.exist(path) method because it is name spaced oddly. The function could be placed directly on Path.exists() instead. (@kirill)

优先规则:

在扩展现有类时,请记住优先规则.它们在 KT-10806 中被描述为:

When extending existing classes, keep the precedence rules in mind. They are described in KT-10806 as:

对于当前上下文中的每个隐式接收器,我们尝试成员,然后是本地扩展函数(还有具有扩展函数类型的参数),然后是非本地扩展.

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.

这篇关于什么时候应该更喜欢 Kotlin 扩展函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆