我不是罗大锤我不是罗大锤

我不是罗大锤

我不是罗大锤我不是罗大锤

我不是罗大锤

首页首页
分类分类
标签标签
友情链接友情
日记日记

在线人数:0 人

文章总浏览量:13406

Powered byNola

Kotlin:使用 infix 构建 更可读的语法Kotlin:使用 infix 构建 更可读的语法

Kotlin:使用 infix 构建 更可读的语法

&Kotlin

允许评论

4 年前

我们已经多次使用过 A to B 这样的语法结构,包括 Kotlin 自带的 mapOf() 函数,这种语法可读性高,相比调用一个函数,它更接近于使用英语的语法来编写。

to 并不是 Kotlin 语言中的一个关键字,之所以我们能使用 A to B 这种语法结构,是因为 Kotlin 提供了一种高级语法糖特性:infix 函数,它只是把编程语言函数调用的语法规则调整了一下,比如 A to B 这样额写法,实际上等价于 A.to(B) 的写法。

下面通过两个具体的例子来学习一下 infix 函数的用法。

一、简单例子

String 类有一个 startsWith() 函数,用于判断一个字符串是否以某个指定参数开头,比如下面的这段代码判断结果一定会是 true:

if ("Hello Kotlin".startsWith("Hello")) {
    // 处理具体逻辑
}

借助 infix 函数,可以使用一种更具可读性的语法来表达这段代码:

// String类扩展函数,给String添加beginsWith函数,通过调用startsWith实现
infix fun String.beginsWith(prefix: String) = startsWith(prefix)

加上 infix 关键字之后,beginsWith() 函数就变成了一个 infix 函数,这样除了传统的函数调用方法之外,还可以使用一种特殊的语法糖格式调用 beginsWith() 函数,如下所示:

// infix允许我们将调用函数的小数点、括号等相关语法去掉
// 从而使用一种更接近英语的语法来编写程序
if ("Hello Kotlin" beginsWith "Hello") {
    // 处理具体逻辑
}

由于 infix 函数的特殊性,有两个比较严格的限制:首先,infix 函数不能定义成顶层函数,它必须是某个类的成员函数,可以使用扩展函数将它定义到某个类当中;其次,infix 函数必须且只能接收一个参数,至于参数类型是没有限制的。

二、复杂例子

这里有一个集合,如果想要判断集合中是否包含某个指定元素,一般可以这样写:

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
if (list.contains("Banana")) {
    // 处理具体逻辑
}

使用 infix 函数让这段代码更具有可读性:

infix fun <T> Collection.<T>.has(element: T) = contains(element)

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
if (list has "Banana")) {
    // 处理具体逻辑
}

三、模仿 to() 函数实现

先看一下 to() 函数的源码:

public infix fun <A,B> A.to(that: B): Pair<A,B> = Pair(this,that)

可以看到这里使用定义泛型函数的方式将 to() 函数定义到了 A 类型下,并且接收一个 B 类型的参数,因此 A 和 B 可以是两种不同类型的泛型,也就使得我们可以构建出字符串 to 整形这样的键值对。

to() 函数的具体实现也非常简单,就是创建并返回了一个 Pair 对象,也就是说 A to B 这样的语法结构实际上得到的是一个包含 A、B 数据的 Pair 对象,而 mapOf() 函数实际上接收的正式一个 Pair 类型的可变参数列表。

下面模仿 to() 函数实现我们自己的一个键值对函数:

infix fun <A,B> A.with(that: B): Pair<A,B> = Pair(this, that)

val map = mapOf("Apple" with 1, "Banana" with 2, "Organge" with 3, "Pear" with 4)
目录
一、简单例子
二、复杂例子
三、模仿 to() 函数实现
暂无评论