功能接收器和扩展功能之间的区别

时间:2017-09-01 11:25:30

标签: kotlin

我正在阅读关于Kotlin的内容并且没有完全理解

从我理解的扩展功能为具有新功能的类提供了能力,而无需从类继承

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

还有别的吗?

有人可以提供一些例子吗

2 个答案:

答案 0 :(得分:6)

扩展功能:

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

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

我们如何用Java编写辅助方法来查找给定的长值是否指向今天?

public class DateUtils {

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

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

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

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

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

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

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

这提高了代码的可读性,从而提高了其可维护性。我们从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和Receiver。

另一个例子:

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

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

调用该功能:

db.inTransaction {
    delete( ... )
}

这里的delete()是SQLiteDatabase类的函数,因为我们传递的lambda是接收器SQLiteDatabase的扩展函数,我们可以访问delete函数而不需要任何其他限定符,就像我们从SQLiteDatabase类本身调用函数一样。

答案 1 :(得分:0)

尽管@Bob的答案在Kotlin上提供的信息比我希望的要丰富得多,包括扩展函数,但它没有直接引用https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver中描述的“带有接收器的函数文字”和扩展名之间的比较。功能(https://kotlinlang.org/docs/reference/extensions.html)。即之间的区别:

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

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

名称的 receiver 部分是指这两种语法都将基本Int参数作为this接收。

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

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

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