糟糕的 Kotlin 语法糖

简介: 糟糕的 Kotlin 语法糖

这几天在 review 同事的代码的时候,发现一块有意思的代码,我将其写成对应的伪代码如下:


class UserViewModel(val userUsecase: UserUsecase) {
    // 根据 userId 获取 userName
    fun getUser(userId:Int) {
        val name = userUsecase(userId).name
    }
}
class User(val name: String, val age: Int) {}
复制代码


起初在看到这段代码的时候,觉得十分反人类,在 Kotlin 中,对象的初始化可以省略 new 操作符,也即类后面再配个 () 即可,为啥一个初始化的对象还能继续用 (),在直观的感受下,我以为是初始化了一个对象,唯一让我觉得不像是初始化的就是 userUsecase 开头并不是大写,这才打消我认为他是初始化对象的疑虑。


在我想点进去看下根据 userId 获取 User 的过程,我无论追踪代码,都无法跳转到真正的逻辑代码调用处,点击 userUsecase 会直接跳转到 UserViewModel 的构造方法,点击 name 会跳转到 User 对象,这让我很苦恼。


我不得不点击 UserUsecase 类去看下里面的代码,这对于 review 人来说简直是灾难,但为了解决问题,先妥协,再一探究竟。


进入 UserUsecase 类,伪代码如下:


class UserUsecase {
    operator fun invoke(userId: Int): User {
        // 从数据库中根据 id 获取 User 数据
        // 返回 User 数据
        return User("lisi", 30)
    }
}
复制代码


看到了奇怪的 invoke 函数,并且是用了 operator 操作重载符,为了了解这种语法,我在 Kotlin 中文网查了下该语法的使用,在调用操作符章节中有所说明:

image.png

对象() 等价于 对象.invoke()()内为函数的参数,也即我们上面的那段代码,可以翻译一下:


class UserViewModel(val userUsecase: UserUsecase) {
    fun getUser() {
        val name = userUsecase(1001).name
        // 等价于
        val name2 = userUsecase.invoke(1001).name
    }
}
复制代码


也可以用 Kotlin Decompile 看下结果:


image.png

需要说明的是,对象() 这种写法是有条件的:


  • 必须用 operator 修饰方法
  • 方法名称必须是 invoke
  • invoke 参数可以多个,不做限制


由于 invoke 函数参数不加限制,这又带来了一个问题,如果重载了多个 invoke 函数,就更不知道业务方在调用的时候是做了什么事情,依然不得不进入代码才能知道逻辑。

上面的示例给的已足够简单,但实际在我们的业务中,比这还复杂,invoke 函数被封装到了父类,当我点进去的时候根本找不到 invoke 函数,只能往上查看父类有没有,在找到 invoke 函数时才发现,他最终调用了个抽象方法,该抽象方法由子类实现,我又不得不返回到子类查看这个方法,最终才敲定这个方法做了什么逻辑。


总结:


虽然 operator invoke 可以省略调用方写函数名这个过程,但需要注意的是,代码无论是类名还是方法名还是变量名,一定要做到见名识意,显然,他已经破坏了这个规则,让 review 人很抓狂。


我也很理解大家对 Jetpack 的热爱,这种写法在官方也有出现,可以参考 Domain Layer 这章。但我想说的是,省略方法名这个过程真的有必要吗?写代码到底是为了炫技还是为了让别人能看懂自己的代码呢?

目录
相关文章
|
运维 监控 数据库
如何实现软件SaaS化
如何实现软件SaaS化
|
6月前
|
传感器 人工智能 算法
聚焦“以技术集成支撑单亩价值创造”与“增加值分配机制区块链存证确权”两大核心本质
“振兴链-技术集成科技小院”以技术集成与区块链为核心,推动农业现代化。通过多维度技术整合(如精准农业、物联网等),突破资源约束,最大化单亩产值;同时利用区块链确权存证,建立透明分配机制,解决传统农业中收益不均问题。技术赋能生产,制度重塑分配,实现效率与公平的平衡,助力乡村振兴与产业升级。典型场景显示,该模式可显著提升单亩价值并确保增值公平分配。
|
监控 关系型数据库 MySQL
初体验:数据库监控、管理和可观测性工具(PMM)
Percona Monitoring and Management (PMM) 是一个开源工具,用于监控MySQL、PostgreSQL和MongoDB的性能。它提供实时监控、数据可视化、故障排除和管理功能,支持本地和云端数据库。要安装PMM,首先需安装Docker,然后通过提供的脚本部署PMM服务器和客户端。在MySQL服务器上创建PMM用户后,使用`pmm-admin`命令添加数据库。访问PMM的HTTPS网址(默认用户名和密码为admin)进行配置。本文还包含了安装Docker和PMM的命令行步骤。
初体验:数据库监控、管理和可观测性工具(PMM)
|
IDE 开发工具 开发者
Kotlin语法 - 函数与Lambda表达式
本教程详细讲解了Kotlin中的函数与Lambda表达式,包括函数的基本定义、默认返回值类型、匿名函数、Lambda表达式的定义及简化、Lambda与函数引用的结合使用,以及如何在Lambda中实现循环控制。适合希望深入了解Kotlin语法的开发者。
150 1
|
11月前
|
缓存 NoSQL Serverless
云数据库Tair:从稳定低延时缓存到 Serverless KV
本次分享聚焦云数据库Tair的使用,涵盖三部分内容:1) Tair概览,介绍其作为稳定低延时缓存及KV数据库服务的特点和优势;2) 稳定低延迟缓存技术,探讨如何通过多线程处理、优化内核等手段提升性能与稳定性;3) 从缓存到Serverless KV的演进,特别是在AI大模型时代,Tair如何助力在线服务和推理缓存加速。Tair在兼容性、性能优化、扩缩容及AI推理加速方面表现出色,满足不同场景需求。
|
11月前
|
人工智能 数据可视化 JavaScript
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
NodeTool 是一个开源的 AI 工作流可视化构建器,通过拖放节点的方式设计复杂的工作流,无需编码即可快速原型设计和测试。它支持本地 GPU 运行 AI 模型,并与 Hugging Face、OpenAI 等平台集成,提供模型访问能力。
545 14
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
|
Web App开发 存储 安全
Python编写脚本,打开浏览器输入网址,自动化登陆网站
Python编写脚本,打开浏览器输入网址,自动化登陆网站
1155 5
|
存储 缓存 Unix
【进程IO】详细讲解文件描述符fd
【进程IO】详细讲解文件描述符fd
|
网络协议 文件存储 Docker
如何搭建HomeAssistant智能家居管理平台并实现公网访问内网管理界面
如何搭建HomeAssistant智能家居管理平台并实现公网访问内网管理界面
|
Java C++
jni传递对象
【5月更文挑战第4天】
209 2