该书“科特琳。 专业人士编程“

图片 嗨,habrozhiteli! 乔什·斯金(Josh Skin)和大卫·格林霍尔(David Greenhall)所著的书是根据《大书呆子牧场》(Big Nerd Ranch)受欢迎的Kotlin Essentials课程编写的。 生动有用的示例,对关键概念和基本API的清晰解释,不仅介绍了Kotlin语言,而且还教了如何有效使用其功能,还使您能够掌握JetBrains IntelliJ IDEA开发环境。

无论您是有经验的开发人员想要超越Java,还是正在学习第一门编程语言,都没有关系。 Josh和David将指导您从Kotlin的基本原理到高级使用,以便您可以创建可靠且高效的应用程序。


这本书是给谁的?


我们(作者)为不同能力的开发人员写了这本书:缺乏Java功能的经验丰富的Android开发人员,对Kotlin功能感兴趣的服务器代码开发人员,以及决定学习有效编译语言的初学者。

本书可能对您支持Android感兴趣,但不仅限于在Android的Kotlin上编程。 此外,在本书中,只有一章(第21章)讨论了Android的Kotlin编程技术。 不过,如果您对使用Kotlin开发Android应用程序的主题感兴趣,则本书将向您介绍可简化在Kotlin上编写Android应用程序的基本技术。

尽管Kotlin受到其他一些语言的影响,但您无需了解它们如何与Kotlin一起成功使用。 我们将不时地比较Java和Kotlin代码。 如果您有使用Java进行开发的经验,这将帮助您了解两种语言之间的关系。 如果您没有这样的经验,那么用另一种语言来解决相同问题的示例将帮助您理解影响Kotlin形成的想法。

如何使用这本书


这本书不是参考。 我们的目标是持续学习Kotlin语言。 您将与项目一起工作,并在此过程中学习语言。 为了获得更好的效果,我们建议您在阅读本书时尝试所有代码示例。 处理示例将帮助您发展“肌肉”记忆并提供见解,使您可以从一章转到另一章。

下一章均基于上一章。 我们建议不要跳过章节。 即使您在使用其他语言时也研究了该主题,我们还是建议您至少在这里阅读该主题:Kotlin中的许多事情都以不同的方式实现。 我们从介绍性主题(例如变量和列表)开始,然后转向面向对象和函数式编程技术,以使您了解使Kotlin如此强大的工具的原因。 在本书的最后,您将从Kotlin的初学者变为高级开发人员。

我们要补充一点,您不要着急:开发并使用Kotlin文档,其链接为: kotlinlang.org/docs/reference ,其中包含实验过程中出现的许多问题的答案。

摘录。 扩展名


扩展允许您在不显式更改类型声明的情况下向类型添加功能。 将扩展名与自定义类型一起使用,以及与您无法控制的类型一起使用,例如List,String和Kotlin标准库中的其他类型。
扩展是继承的替代方法。 如果您无法使用类定义或该类没有允许您创建子类的open修饰符,则它们非常适合为类型添加功能。

Kotlin标准库经常使用扩展名。 例如,您在第9章中学到的标准函数被声明为扩展,在本章中,您将看到一些声明它们的示例。

在本章中,我们将首先处理Sandbox项目,然后将这些知识应用于优化NyetHack代码。 首先,打开Sandbox项目并创建一个名为Extensions.kt的新文件。

扩展功能声明


您的第一个扩展名允许您向String添加任何程度的热情。 在Extensions.kt中声明它。

清单18.1 为字符串类型添加扩展名(Extensions.kt)

fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) 

扩展函数的声明方式与其他函数相同,但有一个区别:定义扩展函数时,还可以指定一种称为接收类型的类型,扩展将在该类型上添加功能。 (回想一下第9章,我们将可扩展类型称为“接收器”。)对于addEnthusiasm函数,指定了一个可接受的String类型。

addEnthusiasm函数的主体只是一个返回字符串的表达式:该字符串的内容以及1个或多个感叹号,具体取决于amount参数的值(默认值为1)。 this关键字引用为其调用扩展名的目标对象的实例(在本例中为String实例)。
现在,您可以为String的任何实例调用addEnthusiasm函数。 通过在主函数中声明一行并调用addEnthusiasm扩展函数以显示结果来尝试新的扩展函数。

清单18.2 调用String接收器对象(Extensions.kt)的实例的新扩展名

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun main(args: Array<String>) { println("Madrigal has left the building".addEnthusiasm()) } 

运行Extensions.kt,并查看扩展功能是否按预期方式在字符串中添加了感叹号。

是否可以继承String的子类以将此功能添加到String实例? 在IntelliJ中,通过按两次Shift键打开“搜索到处”对话框,然后在搜索框中输入“ String.kt”,查看String声明的源代码。 您将看到此类声明:

 public class String : Comparable<String>, CharSequence { ... } 

由于open关键字不在String类的声明中,因此您不能将String子类化以通过继承添加新功能。 如前所述,如果您想向无法管理或无法用于创建子类的类添加功能,扩展是一个不错的选择。

超类扩展声明


扩展不依赖继承,但可以将其与继承结合以扩大范围。 在Extensions.kt中尝试此操作:为类型Any声明一个扩展,名称为easyPrint。 由于该扩展名声明为Any,因此它将适用于所有类型。 在main中,将println函数调用替换为对String的easyPrint扩展调用。

清单18.3 任何扩展名(Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint() = println(this) fun main(args: Array<String>) { println("Madrigal has left the building".addEnthusiasm()).easyPrint() } 

运行Extensions.kt,并确保输出未更改。

由于您为Any类型添加了扩展名,因此它也可用于子类型。 为Int添加扩展呼叫。

清单18.4 easyPrint适用于所有子类型(Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint() = println(this) fun main(args: Array<String>) { "Madrigal has left the building".addEnthusiasm().easyPrint() 42.easyPrint() } 

通用扩展功能


但是,如果要在addEnthusiasm前后打印“ Madrigal已离开建筑物”行,该怎么办?

为此,将调用链的功能添加到easyPrint函数。 您已经看过函数调用的链:如果函数返回接收者对象或可以调用后续函数的另一个对象,则这些函数可以参与链中。
升级easyPrint到呼叫链接。

清单18.5 将easyPrint更改为呼叫链接(Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint()= println(this): Any { println(this) return this } ... 

现在尝试两次调用easyPrint函数:在addEnthusiasm之前和之后。

清单18.6 两次调用easyPrint(Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun Any.easyPrint(): Any { println(this) return this } fun main(args: Array<String>) { "Madrigal has left the building".easyPrint().addEnthusiasm().easyPrint() 42.easyPrint() } 

该代码未编译。 允许进行第一个easyPrint调用,但不允许addEnthusiasm。 查看类型信息以了解发生这种情况的原因:单击easyPrint并按Control-Shift-P(Ctrl-P),然后从出现的扩展名列表中选择第一个:(“ Madrigal已离开建筑物.easyPrint()”) (图18.1)。

easyPrint函数返回为其调用的字符串,但使用Any类型表示它。 addEnthusiasm仅适用于String,因此无法在easyPrint返回的值上调用它。

图片

要解决此问题,可以进行广义扩展。 更新easyPrint扩展功能,并使用通用类型而不是Any作为接受器。

清单18.7 泛化easyPrint(Extensions.kt)

 fun String.addEnthusiasm(amount: Int = 1) = this + "!".repeat(amount) fun <T> AnyT.easyPrint(): AnyT { println(this) return this } ... 

现在,当扩展使用广义类型T的参数作为接收者并返回T而不是Any时,有关接收者对象的特定类型的信息将沿链向下传递(图18.2)。

图片

尝试再次运行Extensions.kt。 这次,该行将被输出两次:

 Madrigal has left the building Madrigal has left the building! 42 

您的新通用扩展功能可与任何类型一起使用,并处理有关它的信息。 使用泛型类型的扩展允许您编写可以在程序中与多种类型一起使用的函数。

Kotlin标准库中还提供了泛型类型的扩展。 例如,查看let函数的声明:

 public inline fun <T, R> T.let(block: (T) -> R): R { return block(this) } 

let被声明为通用扩展函数,从而使其可以与所有类型一起使用。 它使用一个lambda,它将接收者对象作为参数(T),并返回某种新类型R的值。

请注意inline关键字,这是我们在第5章中了解到的。我们在前面给出的相同建议也适用于此:将扩展函数声明为内置函数(如果它接受lambda的话)可以降低内存成本。

»这本书的更多信息可以在出版商的网站上找到
» 目录
» 摘录

Khabrozhitel- Kotlin的优惠券可享受25%的折扣
支付纸质版本的书后,就会通过电子邮件发送电子书。

Source: https://habr.com/ru/post/zh-CN464177/


All Articles