接收函数和扩展函数的区别

问题描述 投票:0回答:2

我正在阅读有关 Kotlin 的内容,但不太明白这个想法

据我了解,扩展函数赋予了具有新功能的类的能力,而无需从类继承

什么是接收者相同,除了它可以分配给变量

还有其他事吗?

有人可以举一些例子吗

kotlin terminology extension-function
2个回答
17
投票

扩展功能:

与 Swift 和 C# 一样,Kotlin 提供了用新功能扩展类的能力,而无需修改类或从类继承。

您可能想知道为什么?因为我们无法对语言或SDK类进行编辑和添加功能。所以我们最终在 Java 中创建 Util 类。我相信所有项目都有一堆 *Utils 类来放置在代码库中多个位置使用的辅助方法。扩展函数有助于解决这个 Util 问题。

我们如何在 Java 中编写一个辅助方法来查找给定的 long 值是否指的是今天?

public class DateUtils {

    public static boolean isToday(long when) {
        // logic ...
    }
}

我们通过传递 long 值作为参数来调用该方法:

void someFunc(long when) {
    boolean isToday = DateUtils.isToday(when);
}

在 Kotlin 中,我们可以扩展 Long 类以在其中包含 isToday() 函数。我们可以像类中的任何其他成员函数一样对 Long 值本身调用 isToday() 函数。

// Extension function
fun Long.isToday(): Boolean {
    // logic ... 
}

fun someFunc(time: Long) {
    val isToday = time.isToday()
}

与 Util 方法相比,Kotlin 使用扩展函数提供了更丰富的语法。

这提高了代码的可读性,进而提高了其可维护性。我们从 IDE 的代码补全中得到了一些帮助。因此我们不必记住使用哪个 Util 类来实现所需的功能。

在底层,Kotlin 编译器生成静态辅助方法,就好像我们将它们编写为 Java 静态 Util 方法一样。因此,我们在 Kotlin 中获得了这种漂亮且更丰富的语法,而无需牺牲任何性能。

与函数类似,Kotlin 也支持扩展属性,我们可以在现有类中添加属性。

高阶函数:

高阶函数是以函数为参数,或者返回一个函数的函数。

让我们看看如何编写高阶函数。

fun execute(x: Int, y: Int, op: (Int, Int) -> Int): Int {
    return op(x, y)
}

这里第三个参数( op )是一个函数,因此它使该函数成为一个高阶函数。参数op的类型是一个函数,以2个Int为参数并返回一个Int。

要调用这个高阶函数,我们可以传递一个函数或 lambda 表达式:

execute(5, 5) { a, b -> a + b }

接收器(或带接收器的函数文字或带接收器的 Lambda):

以扩展函数作为参数的高阶函数称为 Lambda with Receiver。

让我们看一下 Kotlin 标准库中的 apply 函数的实现。

inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

我们传递给这个apply函数的函数实际上是类型T的扩展函数。因此在lambda函数中,我们可以访问类型T的属性和函数,就像我们在类T本身中编写这个函数一样。

这里泛型类型 T 是接收者,我们传递一个 lambda 函数,因此名称为 Lambda with Receiver。

另一个例子:

inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
    beginTransaction()
    try {
        func()
        setTransactionSuccessful()
    } finally {
        endTransaction()
    }
}

这里的inTransaction()是对SQLiteDatabase类的扩展函数,inTransaction()函数的参数也是对SQLiteDatabase类的扩展函数。这里 SQLiteDatabase 是作为参数传递的 lambda 的接收者。

调用该函数:

db.inTransaction {
    delete( ... )
}

这里的delete()是

SQLiteDatabase
类的函数,并且由于我们传递的lambda是接收者的扩展函数
SQLiteDatabase
我们可以访问delete函数而不需要任何额外的限定符,就像我们调用从
SQLiteDatabase
类本身内部调用函数。


7
投票

虽然 @Bob 的回答关于 Kotlin 的信息比我希望的要丰富得多,包括扩展函数,但它并没有直接引用 https://kotlinlang.org/ 中描述的“函数文字与接收器”之间的比较docs/reference/lambdas.html#function-literals-with-receiver 和扩展函数 (https://kotlinlang.org/docs/reference/extensions.html)。 IE。之间的区别:

val isEven: Int.() -> Boolean = { this % 2 == 0 }

fun Int.isEven(): Boolean = this % 2 == 0

名称中的 receiver 部分是指这两种语法都将基本

Int
参数接收为
this

据我了解,两者之间的区别仅在于一个是确认函数类型的表达式,另一个是声明。从功能上来说,它们是等效的,都可以称为:

when { myNumber.isEven() -> doSomething(myNumber) }

但其中一个旨在用于扩展库,而另一个通常用作具有函数类型参数的函数的参数,特别是 Kotlin 构建器 DSL。

© www.soinside.com 2019 - 2024. All rights reserved.