糟糕的 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 这章。但我想说的是,省略方法名这个过程真的有必要吗?写代码到底是为了炫技还是为了让别人能看懂自己的代码呢?

目录
相关文章
|
安全 IDE Java
又被 Kotlin 语法糖坑惨的一天
又被 Kotlin 语法糖坑惨的一天
206 0
又被 Kotlin 语法糖坑惨的一天
|
XML 存储 缓存
怎么用Kotlin去提高生产力:Kotlin Tips
汇总Kotlin相对于Java的优势,以及怎么用Kotlin去简洁、务实、高效、安全的开发,每个小点tip都有详细的说明和案例代码,争取把每个tip分析得清楚易懂,会不断的更新维护tips,欢迎fork进来加入我们一起来维护,有问题的话欢迎提Issues。 • 推荐一个Kotlin的实践项目debug_view_kotlin,用kotlin实现的Android浮层调试控制台,实时的显示内存、FPS、文字log
221 1
|
Java Kotlin
【Kotlin 初学者】函数(方法)(下)
函数 函数(function)和方法(method)这两个概念经常被混淆,他们到底有什么关联和区别?其实,它俩没有什么区别只是不同语言叫法不一样,在Java中普遍叫方法。而在Kotlin中普遍叫函数。重点是:函数(function)和方法(method)是同一个东西,别搞错了。
153 0
【Kotlin 初学者】函数(方法)(下)
|
Java Android开发 Kotlin
【Kotlin 初学者】函数(方法)(上)
目录 函数 函数头 实践 函数参数 实践 Unit函数 Nothing类型 实践 反引号中的函数名 使用空格和特殊字符对函数命名 实践 Kotlin和Java互操作
200 0
【Kotlin 初学者】函数(方法)(上)
|
存储 安全 Java
【Kotlin 初学者】泛型简单剖析与使用
一、泛型使用 泛型,即 "参数化类型",将类型参数化,可以用在类,接口,函数上。 与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
248 0
【Kotlin 初学者】泛型简单剖析与使用
|
Java 编译器 Kotlin
聊聊Kotlin中的元编程
聊聊Kotlin中的元编程
316 0
聊聊Kotlin中的元编程
|
安全 Java 编译器
Kotlin刨根问底(一):你真的了解Kotlin中的空安全吗?(下)
行文结构:要点提炼(方便回顾) + 常规操作 + 源码层面摸索实现原理, 内容部分摘取自:《Kotlin实用指南》
138 0
|
安全 Java Kotlin
Kotlin刨根问底(一):你真的了解Kotlin中的空安全吗?(上)
行文结构:要点提炼(方便回顾) + 常规操作 + 源码层面摸索实现原理, 内容部分摘取自:《Kotlin实用指南》
212 0
|
Java Kotlin
Kotlin刨根问底(三):你真的懂泛型,会用吗?(中)
本文灵感来源:群友提出泛型相关的问题,感觉很多人对泛型并不是很了解~ Kotlin中的泛型和Java中的泛型其实大同小异,只是语法稍微有些不同。 大部分内容摘取自:《Kotlin实用指南》
128 0
|
Java Android开发 Kotlin
Kotlin刨根问底(三):你真的懂泛型,会用吗?(下)
本文灵感来源:群友提出泛型相关的问题,感觉很多人对泛型并不是很了解~ Kotlin中的泛型和Java中的泛型其实大同小异,只是语法稍微有些不同。 大部分内容摘取自:《Kotlin实用指南》
167 0