什么时候应该选择Kotlin扩展功能? [英] When should one prefer Kotlin extension functions?

查看:100
本文介绍了什么时候应该选择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)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时.扩展功能是通过添加新功能来更改类的惯用方式.您可以添加扩展功能

  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上调用的新方法或现有方法添加null安全性.例如,字符串String?.isNullOrBlank()的扩展功能允许您甚至在null字符串上使用该功能,而不必先进行自己的null检查.函数本身在调用内部函数之前会进行检查.请参阅有关具有Nullable Receiver的扩展的文档

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,当前不是在接口内允许).当您需要内联修饰函数时,这很有用,

  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()扩展方法,该方法遵循循环文档-甚至返回的类似迭代器的对象也可以使用扩展来满足提供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天全站免登陆