热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Kotlin中扩展函数的惯用用法及其合理性

本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。

我看到 Kotlin 中扩展函数的一些用法我个人认为这没有意义,但似乎有一些指导方针“显然”支持它(解释问题)。

具体来说:在类之外(但在同一个文件中)定义一个扩展函数:

data class AddressDTO(val state: State,
val zipCode: String,
val city: String,
val streetAddress: String
)
fun AddressDTO.asXyzFormat() = "${streetAddress}n${city}n${state.name} $zipCode"

其中asXyzFormat()被广泛使用,并且不能被定义为专用/内部(也为情况下,可能)。

在我的常识中,如果您拥有代码 ( AddressDTO) 并且用法不是某个类/模块的本地(因此是私有/内部) - 没有理由定义扩展函数 - 只需将其定义为成员函数班级。


  • 边缘情况:如果你想避免从get-开始的函数序列化- 注释类以获得所需的行为(例如@JsonIgnore在函数上)。这个恕我直言仍然不能证明扩展功能是合理的。

我对此的反驳是,官方 Kotlin 编码约定支持这种方式的扩展功能。具体来说:

自由地使用扩展函数。每次你有一个主要作用于一个对象的函数时,考虑使它成为一个接受该对象作为接收者的扩展函数。

来源

和:

特别是,当为与该类的所有客户端相关的类定义扩展函数时,请将它们放在定义类本身的同一文件中。在定义仅对特定客户端有意义的扩展函数时,将它们放在该客户端的代码旁边。不要创建文件只是为了保存“Foo 的所有扩展名”。

来源

我将感谢任何普遍接受的来源/参考解释为什么将函数移动为类的成员和/或实用参数支持这种分离更有意义。

回答


关于自由使用扩展函数的引用,我很确定意味着自由使用它们而不是顶级非扩展函数(而不是使它成为成员函数)。这是说,如果顶级函数在概念上适用于目标对象,则更喜欢扩展函数形式。

我之前曾搜索过为什么在处理拥有源代码的类时可能选择将函数作为扩展函数而不是成员函数的答案,但从未从 JetBrains 找到规范的答案。以下是我认为您可能会遇到的一些原因,但有些原因很受意见的影响。


  • 有时您需要一个函数来操作具有特定泛型类型的类。想想List.sum(),它仅适用于 Lists 的子集,而不适用于 List 的子类型。

  • 接口可以被认为是契约。接口执行某些操作的函数在概念上可能更有意义,因为它们不是合同的一部分。我认为这是 Iterable 和 Sequence 的大多数标准库扩展函数的基本原理。如果您认为数据类几乎像一个被动结构,则类似的原理可能适用于数据类。

  • 扩展函数提供了允许用户伪覆盖它们的可能性,但强制它们以独立的方式进行。假设你asXyzFormat()是一个开放的成员函数。在其他一些模块中,您收到 AddressDTO 实例并希望以您期望的格式获取它们的 XYZ 格式。但是您收到的 AddressDTO可能已被覆盖asXyzFormat()并为您提供了一些意想不到的东西,所以现在您不能信任该功能。如果您使用扩展功能,那么您允许用户asXyzFormat()用适用于该空间的内容替换他们自己的包中的内容,但您始终可以信任asXyzFormat()源包中的功能。



  • 与接口类似,具有默认实现的成员函数会邀请用户覆盖它。作为接口的作者,您可能需要一个可靠的函数,您可以在该接口上使用具有预期行为的函数。尽管最终用户可以通过重载将您的扩展隐藏在他们自己的模块中,但这不会影响您自己对该功能的使用。

就其价值而言,我认为当您拥有类(而不是接口)的源代码时,很少会选择为类(而不是接口)制作扩展函数。我想不出标准库中的任何例子。这让我相信编码约定文档在包括接口的自由意义上使用“类”一词。






推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文详细记录了在基于Debian的Deepin 20操作系统上安装MySQL 5.7的具体步骤,包括软件包的选择、依赖项的处理及远程访问权限的配置。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
author-avatar
手机用户2702935897
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有