迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 >

区分 Kotlin 中的扩展函数

作者:迹忆客 最近更新:2023/03/21 浏览次数:

在面向对象编程中,我们学习了继承、封装、抽象和多态的概念,但这些不足以以灵活、可重用和可维护的方式构建我们的应用程序。

设计模式,在设计原则和 OOP 概念的帮助下,提供了解决方案来解决常见的设计问题。一种与我们将在本教程中介绍的非常相似的设计模式是装饰器设计模式。

装饰器设计模式允许我们向应用程序添加功能,而无需从另一个类扩展。在 Kotlin 中,我们可以通过使用 Kotlin 扩展函数来实现相同的功能设计模式。

Kotlin 中的扩展函数向一个类添加功能,而无需从另一个类扩展或使用装饰器设计模式。在幕后,扩展函数可以是泛型的,可以使用 lambda 函数来实现我们提到的功能。

在本文中,我们将深入了解每个扩展函数,并为每个函数提供一个示例。本文介绍的扩展函数包括:apply()also()let()takeIf()takeUnless()

在 Kotlin 中创建扩展函数

要创建扩展函数,请定义要添加功能的类型,例如字符串、数字或类,并使用点运算符定义委托功能的方法。定义扩展函数的返回类型,最后在同一行实现方法的逻辑。

转到 Intellij 代码编辑器并创建一个名为 extension-exercise 的新项目。在 src 下,创建文件夹结构 com.extension

extension 文件夹下创建一个 Main.kt 文件并粘贴以下代码。

package com.extension

fun Number.isGreaterThanTen(): Boolean = this.toInt() > 10;

fun main() {
    val  num = 100;
    println(num.isGreaterThanTen());
}

在上面的代码中,我们在 Number 类型上定义了一个名为 isGreaterThanTen() 的扩展函数,它检查一个数字是否大于 10 并返回一个布尔值。

如果你从此时开始调用任何 number 类型的变量,你将可以访问 isGreaterThanTen() 方法,如上面的 main 方法所示。

请注意,当你运行上述程序时,会在控制台中记录布尔值 true

true

在 Kotlin 中使用 Lambda 函数和扩展函数

在幕后,一个 lambda 函数可以定义为一个只包含一个方法的接口。lambda 函数匿名传递给具体函数,无需指定函数名称,然后使用箭头符号定义返回类型。

创建另一个文件并将之前的代码移动到该文件中。将以下示例复制并粘贴到空的 Main.kt 文件中。

package com.extension

fun Number.isGreaterThanTen(block: (Number) -> Boolean): Boolean = block(this);

fun main() {
    val num = 100;
    println(num.isGreaterThanTen { number ->
        number.toInt() > 10
    })

}

在上面的代码中,我们定义了一个名为 isGreaterThanTen() 的扩展函数,它接受一个 lambda 函数作为参数并返回一个布尔值。

我们命名为 block 的 lambda 函数接受 Number 类型的参数并返回一个布尔值。lambda 函数返回的这个布尔值被委托给扩展函数。

与前面的示例相比,我们在对主函数内的任何 Number 类型的变量调用 isGreaterThanTen() 后定义扩展函数的逻辑。

运行上面的代码,观察我们得到的结果和前面的例子一样。输出如下图所示。

true

在 Kotlin 中使用 let() 扩展函数

将之前的代码移动到我们创建的新文件中,并将以下代码粘贴到 Main.kt 文件中。

package com.extension

inline fun <T, R> T.let(block: (T) -> R): R = block(this);

fun  main(){
    val num = 10;
    val result = num.let { number -> number.toString() }
    println(result);
    println(result::class.java.typeName);
}

let() 函数是使用泛型定义的,这意味着它可以使用任何类型。调用 let() 函数的对象作为 lambda 函数的参数传递。

lambda 函数在 let() 函数内部定义,并返回与作为参数传递的对象不同的对象。

由于 let() 函数返回的值与 lambda 函数返回的函数相同,我们将 lambda 函数返回值委托给 let() 函数。

在 main 方法中,我们定义了一个 Number 类型的变量,并调用我们的扩展函数来返回数字的字符串表示形式。

然后,我们将返回的值及其类型记录到控制台,以验证扩展功能是否按要求工作。请注意,传递给扩展函数的类型是数字,但返回的值是字符串,如下所示。

10
java.lang.String

在 Kotlin 中使用 also() 扩展函数

将之前的代码移动到我们创建的新文件中,并将以下代码粘贴到空的 Main.kt 文件中。

package com.extension

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

fun main(){
    val  num = 10;
    num.also {i ->
        println(i == 10)
    }
}

调用 also() 扩展函数的对象作为 lambda 函数的参数传递。lambda 函数被定义为扩展函数的参数,并且不返回任何通常由 Unit 表示的值。

also() 函数返回你正在使用的当前变量,该变量被委托给 lambda 函数以进行进一步计算。在 main 函数中,我们定义了一个 Number 类型的变量,委托给 lambda 函数来检查值是否等于 10。

运行代码并注意它返回一个真值,如下所示。

true

在 Kotlin 中使用 apply() 扩展函数

将之前的代码移动到我们创建的新文件中,并将以下代码粘贴到空的 Main.kt 文件中。

package com.extension

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

fun main(){
    val num = 10;
    num.apply {
        println(toDouble());
    }
}

调用 apply() 扩展函数的对象作为该对象的方法调用传递给 lambda 函数的参数。lambda 函数没有返回值。

该定义意味着我们不必使用类型的对象来调用方法,因为 lambda 函数会处理该功能。在这种情况下,我们只需要从一个类型中调用我们需要的方法。

在主函数中,我们定义了一个 Number 类型的变量,并使用 apply() 方法,我们通过调用 toDouble() 方法将 Number 转换为 Double。请注意,没有使用对对象的引用来调用 toDouble() 方法。

运行上面的代码,注意记录到控制台的值是 Double,如下图。

10.0

在 Kotlin 中使用 takeIf() 扩展函数

将之前的代码移动到我们创建的新文件中,并将以下代码粘贴到空的 Main.kt 文件中。

package com.extension

inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

fun main() {
    val  num = 10;
    println(num.takeIf { i ->
        i.plus(10) < 30
    })
}

调用 takeIf() 扩展函数的对象作为 lambda 函数的参数传递。lambda 函数作为此方法的参数传递,并返回一个布尔值。

仅当 lambda 表达式的条件计算为 true 时,扩展函数才返回调用对象。否则,它返回一个 null 值。

在主函数中,我们定义了一个 Number 类型的值,它使用 takeIf() 来确定这个数字加 10 是否小于 30。如果条件评估为真,则返回值 10;否则,返回一个 null 值。

运行上面的代码,注意 lambda 表达式的计算结果为 true,并返回值 10,如下所示。

10

在 Kotlin 中使用 takeUnless() 扩展函数

将之前的代码移动到我们创建的新文件中,然后将以下代码复制并粘贴到空的 Main.kt 文件中。

package com.extension

inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null

fun main() {
    val num = 10;
    println(num.takeUnless { i ->
        i.plus(10) < 30
    })
}

调用 takeUnless() 扩展函数的对象作为 lambda 函数的参数传递。lambda 函数在此方法中定义并返回一个布尔值。

takeIf()takeUnless() 之间的区别在于,此示例仅在 lambda 表达式的计算结果为 false 时返回一个值。这意味着扩展函数返回的值是 lambda 函数返回的布尔函数的倒数。

在 main 方法中,我们定义了与上面相同的示例,但请注意,此示例将返回 null,因为 lambda 函数的计算结果为 true,它被反转为 false

null

结论

本文教我们如何使用扩展函数在 Kotlin 中添加功能。涵盖的扩展函数包括:使用 let()also()apply()takeIf()takeUnless()

请注意 ,这些扩展函数已经在 Kotlin API 中定义,你不必像我们在本教程中所做的那样定义它们。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

如何在 Java 中延迟几秒钟的时间

发布时间:2023/12/17 浏览次数:217 分类:Java

本篇文章主要介绍如何在 Java 中制造程序延迟。本教程介绍了如何在 Java 中制造程序延时,并列举了一些示例代码来了解它。

如何在 Java 中把 Hashmap 转换为 JSON 对象

发布时间:2023/12/17 浏览次数:187 分类:Java

它描述了允许我们将哈希图转换为简单的 JSON 对象的方法。本文介绍了在 Java 中把 Hashmap 转换为 JSON 对象的方法。我们将看到关于创建一个 hashmap,然后将其转换为 JSON 对象的详细例子。

如何在 Java 中按值排序 Map

发布时间:2023/12/17 浏览次数:171 分类:Java

本文介绍了如何在 Java 中按值对 Map 进行排序。本教程介绍了如何在 Java 中按值对 Map 进行排序,并列出了一些示例代码来理解它。

如何在 Java 中打印 HashMap

发布时间:2023/12/17 浏览次数:192 分类:Java

本帖介绍了如何在 Java 中打印 HashMap。本教程介绍了如何在 Java 中打印 HashMap 元素,还列举了一些示例代码来理解这个主题。

在 Java 中更新 Hashmap 的值

发布时间:2023/12/17 浏览次数:146 分类:Java

本文介绍了如何在 Java 中更新 HashMap 中的一个值。本文介绍了如何在 Java 中使用 HashMap 类中包含的两个方法-put() 和 replace() 更新 HashMap 中的值。

Java 中的 hashmap 和 map 之间的区别

发布时间:2023/12/17 浏览次数:79 分类:Java

本文介绍了 Java 中的 hashmap 和 map 接口之间的区别。本教程介绍了 Java 中 Map 和 HashMap 之间的主要区别。在 Java 中,Map 是用于以键值对存储数据的接口,

在 Java 中获取用户主目录

发布时间:2023/12/17 浏览次数:218 分类:Java

这篇文章向你展示了如何在 Java 中获取用户主目录。本教程介绍了如何在 Java 中获取用户主目录,并列出了一些示例代码以指导你完成该主题。

Java 中 size 和 length 的区别

发布时间:2023/12/17 浏览次数:179 分类:Java

这篇文章教你如何知道 Java 中大小和长度之间的区别。本教程介绍了 Java 中大小和长度之间的区别。我们还列出了一些示例代码以帮助你理解该主题。

Java 中的互斥锁

发布时间:2023/12/17 浏览次数:111 分类:Java

了解有关 Java 中互斥锁的一切,在计算机科学领域,互斥或互斥被称为并发控制的属性。每台计算机都使用称为线程的最小程序指令序列。有一次,计算机在一个线程上工作。为了更好地理解,

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便