Kotlin编程权威指南(txt+pdf+epub+mobi电子书下载)


发布时间:2020-11-18 16:40:29

点击下载

作者:(美) 乔希·斯基恩(Josh Skeen),(美) 戴维·格林哈尔希(David Greenhalgh)

出版社:人民邮电出版社有限公司

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Kotlin编程权威指南

Kotlin编程权威指南试读:

前言

2011年,JetBrains宣布开发Kotlin编程语言。这门新语言可以用来编写在Java虚拟机上运行的代码,是Java和Scala语言之外的又一选择。六年后,Google宣布,Kotlin正式获得官方支持,可用于Android应用开发。Kotlin的应用范围迅速扩展,它从一门前途光明的编程语言摇身一变,成了这个世界上最重要的移动操作系统的钦定开发语言。Kotlin语法简洁,具备现代高级语言特性,并且能和Java遗留代码无缝互操作。因为具备这些优势,今天,越来越多的大公司已开始接纳Kotlin,如Google、Uber、Netflix、Capital One、Amazon等。为什么要学Kotlin要想知道为什么Kotlin广受欢迎,首先要理解Java在现代软件开发领域中所扮演的角色。这两门语言联系得非常紧密,因为很多时候,Kotlin代码的开发目标就是要在Java虚拟机上运行。Java语言比较稳健,久经考验。多年来,它一直是最常用的一种编程语言,造就了庞大的生产代码库。自从1995年Java问世以来,对于优秀的编程语言应满足什么条件,人们已通过实践积攒了很多经验教训。然而,Java却裹足不前,开发者喜欢的很多现代语言高级特性,它都没有,或者迟迟才加入。Kotlin从这些经验教训中受益良多,而Java(和其他语言,比如Scala)中的某些早期设计却愈显陈旧。脱胎于旧语言,Kotlin解决了它们的很多痛点,进化成了一门优秀的语言。相比Java,Kotlin进步巨大,带来了更可靠的开发体验。至于它是怎么做到的,本书会一一解答。作为一门新秀语言,Kotlin不仅支持编写代码在虚拟机上运行,而且还是一门跨平台的通用型语言:你可以用Kotlin开发各种类型的原生应用,如macOS应用、Windows应用、JavaScript应用,当然还有Android应用。平台独立性意味着Kotlin有各种各样的用途。本书读者对象本书适合各类开发人员:有经验的Android开发者,他们需要Java所不具备的现代语言特性;对Kotlin感兴趣的后端开发者;想选一门高性能的编译型语言来学习的新手。支持Android开发可能是你阅读本书的理由,但本书内容并不局限于用Kotlin开发Android应用。事实上,除了专门讨论Android开发的第21章,本书所有的Kotlin代码只是兼容Android开发框架而已。也就是说,如果你对使用Kotlin开发Android应用感兴趣,本书介绍的一些常用编程模式会让基于Kotlin的Android应用开发更轻松些。Kotlin博采众长,受很多语言影响,但这并不表示你要掌握其他语言才能学习Kotlin。本书时不时会讨论与Kotlin代码等效的Java代码。如果有Java编程经验,理解这两种语言的关系会更容易。没有的话,看Java如何解决同一问题,会帮助你掌握Kotlin语言特性的原理。如何使用本书本书不是参考指南。我们的目标是带你学习Kotlin编程语言的关键部分。你将学习搭建各种示例项目,在此过程中,一步步掌握Kotlin的基础知识。为了充分利用本书,建议你一边阅读一边输入并测试各种代码示例。这样会有助于你形成“肌肉记忆”,带着逐渐积累的知识,攻克一章又一章。另外,每章主题都是基于上一章内容编排的,所以最好不要跳读。即使你觉得某个章节的内容和其他语言里的差不多,也应该读上一遍,因为处理同样的问题,Kotlin有自己特别的地方。本书首先介绍像变量、集合这样的主题,然后学习面向对象编程和函数式编程技术,这么一路走来,你就会明白为什么Kotlin语言这么强大。学完本书,你将掌握Kotlin基础知识,从一名新手蜕变成更高级的开发者。总之,一定要多花时间。掌握了基础知识之后,还应进一步深入扩展学习。Kotlin语言的参考网站是https://kotlinlang.org/docs/reference。遇到任何新奇的知识点时,请随时查阅并动手实践。深入学习大部分章末包含一节或多节名为“深入学习”的内容。其中,有不少小节用来阐述Kotlin语言的底层运行机制。需要说明的是,各章的代码示例不依赖于这些小节的内容,但它们提供了你可能感兴趣或对你有帮助的额外信息。挑战练习大部分章末配有练习题。设计这些额外的练习是为了帮你进一步理解1Kotlin语言。希望你能接受挑战,多多练习,努力提高Kotlin技能。1读者可前往本书图灵社区页面(http://www.ituring.com.cn/book/2610)下载练习题答案。——编者注排版约定在创建本书中的一个个项目时,我们会先讨论一个主题,然后一步步带你在项目里运用所学知识。为了方便读者阅读,本书采用以下排版约定。变量、值和类型,以及类、函数、接口名都以等宽字体显示。所有代码清单都以等宽字体显示。需要输入的代码总是以粗体显示。应该删除的代码会打上删除线。例如,下列代码表示,你需要删除y变量定义,添加z变量定义。var x = "Python"var y = "Java"var z = "Kotlin"Kotlin是一门相对年轻的语言,所以很多编码规则还在制定中。时间一长,你可能就会创造出自己的编码风格,不过我们倾向于遵循JetBrains和Google的Kotlin编码风格指南。● JetBrains的编码约定:https://kotlinlang.org/docs/reference/

coding-conventions.html。● Google的代码指南,包括Android代码和互操作的编码约定:

https://android.github.io/kotlin-guides/style.html。展望未来本书的示例需要你多花点时间。一旦掌握了Kotlin语法,你的开发过程就会变得清晰、务实和顺畅。即便达到了一定水平,你也应坚持前行,不断进步。最终,你会体会到,学习一门新语言真的太有收获了。电子书扫描如下二维码,即可购买本书电子版。第 1 章 Kotlin应用开发初体验本章,你将学习使用IntelliJ IDEA开发首个Kotlin应用。借此,你将熟悉开发环境,创建Kotlin新项目,编写并运行Kotlin代码,以及查看输出结果。本章创建的是一个沙盒项目,可供你演练代码,以学习理解本书中的各种新概念。1.1 安装IntelliJ IDEAIntelliJ IDEA是一套Kotlin集成开发环境。JetBrains公司创建了Kotlin语言并打造出了这套开发工具。开始学习前,请先访问JetBrains公司网站https://www.jetbrains.com/idea/download,下载IntelliJ IDEA社区开发版软件(见图1-1)。图1-1 下载IntelliJ IDEA社区开发版软件下载完毕后,请参考https://www.jetbrains.com/help/idea/install-and-set-up-product.html网页,完成对应平台IntelliJ IDEA开发工具的安装与配置。IntelliJ IDEA简称IntelliJ,能帮助开发者编写风格良好的Kotlin代码。利用其内建工具,运行、调试、检查以及重构代码的整个开发过程能无缝衔接,一气呵成。有鉴于此,我们推荐使用IntelliJ做Kotlin开发。若想进一步了解使用IntelliJ做Kotlin开发的理由,请阅读1.4节。1.2 第一个Kotlin项目恭喜你,Kotlin语言及强大的开发环境都有了,接下来只剩一件事要做:学会流畅运用Kotlin语言。作为首个练手任务,我们来创建一个Kotlin项目。启动IntelliJ。如图1-2所示,映入眼帘的是IntelliJ IDEA的欢迎界面。图1-2 欢迎界面(若非首次安装使用,IntelliJ会直接打开上一个项目。要回到欢迎界面,选择File → Close Project关闭项目即可。)单击Create New Project选项,会看到如图1-3所示的创建新项目对话框。图1-3 创建新项目对话框在创建新项目对话框中,选择左侧的Kotlin选项,然后选择右边出现的Kotlin/JVM选项,结果如图1-4所示。图1-4 创建一个Kotlin/JVM项目除了Kotlin,IntelliJ还支持Java、Python、Scala以及Groovy等其他编程语言。选择Kotlin/JVM就是告诉IntelliJ你要用Kotlin编程。更确切地讲,就是要编写面向并且在Java虚拟机上运行的Kotlin代码。顺便提一下,Kotlin还有个优势:内置的工具链支持编写能在不同操作系统和平台上运行的Kotlin代码。(从现在起,提到Java虚拟机,本书都以Java开发社区常用的JVM来替代。1.5节还会介绍更多有关面向JVM的知识。)单击Next按钮继续。你会看到新项目设置界面,如图1-5所示。输入“Sandbox”作为项目名称,IntelliJ会自动给出默认项目路径。如有需要,可以单击右侧的…按钮自定义项目路径。在Project SDK的下拉框中点选Java 1.8,这样,新项目就关联上了JDK 8。图1-5 给新项目命名你可能会问,编写Kotlin程序为什么需要JDK?答案就是,为了把Kotlin代码转译为字节码(稍后详述),IntelliJ需要JDK提供JVM和Java工具。理论上讲,JDK 6及其后的版本都能用,但是经验表明,至本书撰稿之时,还是JDK 8用起来更顺畅。如果在Project SDK下拉框里看不到Java 1.8,说明你还没有安装过JDK 8。继续学习之前,请先访问https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html,下载相应平台的安装包完成安装,然后重启IntelliJ使其生效。最后,按照前述步骤从头开始创建新项目。言归正传,确认新项目设置如图1-5所示,然后单击Finish按钮。如图1-6所示,IntelliJ随即创建一个名为Sandbox的新项目,并在默认的双面板视图里显示出来。反映在硬盘上,IntelliJ会在项目指定路径创建一个文件夹、一系列子文件夹以及对应的项目文件。图1-6 默认的双面板视图图1-6中,左面板显示的是项目工具窗口。右面板现在空着。待会你会看到,这里会显示编辑器窗口,供你查看和编辑Kotlin代码文件。先来看左边的项目工具窗口。单击项目名称Sandbox左侧的展开箭头,可以展现项目包含的文件,如图1-7所示。图1-7 项目视图在IntelliJ中,项目既包含我们应用的所有源代码,也包含有相关的依赖和配置信息。项目可以分成一个或多个类似于子项目的模块。新建项目默认含有一个模块,对于简单的Kotlin项目来说,一个就够了。如图1-7所示,Sandbox.iml文件包含项目模块的配置信息。.idea文件夹存放整个项目的设置文件,以及用户在IDE中和项目交互相关的设置文件(例如,当前编辑器打开了哪个文件)。上述文件都是系统自动生成的,现在不用管它们。External Libraries项包含项目依赖库的信息。单击展开该项,可以看到,IntelliJ已自动为项目添加了Java 1.8以及KotlinJavaRuntime依赖库。(想了解更多有关IntelliJ项目结构的知识,请访问JetBrains文档网址:https://www.jetbrains.org/intellij/sdk/docs/basics/project_structure.html。)src文件夹用来存放为Sandbox项目创建的所有Kotlin代码文件。好了,是时候来创建并编辑首个Kotlin代码文件了。1.2.1 创建首个Kotlin文件在项目工具窗口中,右击src文件夹。如图1-8所示,在弹出的菜单中,依次选择New和Kotlin File/Class菜单项。图1-8 新建一个Kotlin文件在New Kotlin File/Class对话框中,在Name处输入文件名“Hello”,保持Kind处的File选项不变(见图1-9)。图1-9 给Kotlin文件命名单击OK按钮确认。如图1-10所示,IntelliJ随即新建了src/Hello.kt这样一个项目文件,同时在IntelliJ右边窗口的编辑器里打开该文件。我们知道,.java后缀用于Java文件,.py后缀用于Python文件,同样,.kt后缀说明新建文件存放着Kotlin代码。图1-10 编辑器中的Hello.kt空文件现在,可以开始编写Kotlin代码了。在Hello.kt编辑器中,动动手,输入代码清单1-1所示的代码。(注意,本书中所有需要读者输入的代码都显示为粗体。)

代码清单1-1 “Hello,World!”Kotlin语言版(Hello.kt)fun main(args: Array) { println("Hello, world!")}不太明白刚刚输入的代码?不要担心,学完本书,你一定能自然、流利地读写Kotlin代码。现在只要大致知道是输出“Hello,World!”字符串就可以了。代码清单1-1中的代码定义了一个main新函数。函数实际就是一组可以稍后运行的代码指令。我们将在第4章中具体学习如何定义并使用函数。对于Kotlin语言来讲,main函数有特别的意义。它是应用程序开始启动的地方,又称为应用程序入口点。Sandbox或任何应用程序要能运行,都必须定义这样的入口点。本书编写的所有应用程序都从main函数开始启动。上述代码中的main函数仅包含一条指令(也叫语句):println("Hello, world!")。println()也是个函数,内置于Kotlin标准库中。Sandbox应用程序一旦运行,println("Hello, world!")就会执行,IntelliJ随即在屏幕上输出圆括号中的Hello, world!字符串。1.2.2 运行Kotlin文件如图1-11所示,一旦输入完代码清单1-1中的代码,在第一行代码左侧,会出现一个绿色的运行按钮。(如果绿色运行按钮没出现,或者Hello.kt文件名或某段代码下方被打上了红色波浪线,则说明代码有误,请对照代码清单1-1仔细核对修改。另外,如果看到Kotlin的红蓝K标志也没问题,它相当于运行按钮。)图1-11 运行按钮代码无误的话,Hello, world!应用程序就可以运行了。如图1-12所示,单击运行按钮,选择Run ‘HelloKt’菜单项。这相当于告诉IntelliJ,你想看着应用程序运行起来。图1-12 运行Hello.kt文件应用程序运行时,IntelliJ就一行一行执行花括号({})里的代码,同时在IDE界面底部显示两个新工具窗口,如图1-13所示。图1-13 运行和事件日志工具窗口图1-13中,左边是运行工具窗口,又叫控制台(后续都这样称呼)。控制台显示IntelliJ执行应用程序时产生的各种信息,也包括应用程序本身的输出。就本例来说,你会看到控制台显示Hello, world!字符串,还会看到标志应用程序成功执行的语句:Process finished with exit code 0。这条语句会出现在控制台各种输出信息的最后。你知道就好,本书后续截图将不再包括此信息。(macOS用户可能会看到红色的错误文本,指出JavaLauncherHelper有问题,如图1-13所示。不要担心。这是在macOS上安装Java运行时环境的方式所带来的副作用。要想移除它得费一番工夫,不过这个问题并没有什么影响,所以你大可忽略它,继续操作。)图1-13中,右边是事件日志工具窗口。该窗口显示IntelliJ为应用程序执行所做工作的相关信息。显然,控制台才是我们要关心的地方,所以事件日志窗口后续不会再提起。(同理,你也不用管事件日志窗口在应用程序运行时是否打开。)要关闭事件日志窗口,单击右上角的隐藏按钮即可。编译并运行Kotlin代码从点选Run ‘HelloKt’菜单项至控制台输出Hello, World!结果只需很短的时间,但后台实际已忙活了不少事。首先,IntelliJ使用kotlinc-jvm编译器编译Kotlin代码。具体来讲,就是把Kotlin代码转换为JVM语言:字节码。转换过程中,如有问题,kotlinc-jvm会报错并给出排错提示;一切顺利的话,IntelliJ就进入执行阶段。在执行阶段,kotlinc-jvm生成的字节码会在JVM上执行。控制台随后会打印程序输出,例如,在JVM一条条执行指令时,调用println()函数会输出传入其中的文字。字节码指令执行完毕后,JVM随即终止。IntelliJ在控制台显示终止状态,告诉用户执行成功完成或是有错并给出错误码。第2章会深入探讨字节码的相关知识,不过,这里要说的是,即使不能完全理解Kotlin的编译过程,也不妨碍你阅读本书。1.3 Kotlin REPL就像拿张稿纸就某个计算一步步演算那样,有时候,你可能需要测试一小段Kotlin代码,看看运行结果如何。这在学习Kotlin语言时非常有用。幸运的是,IntelliJ就提供了这种工具,能够实现无须创建文件就快速测试代码。该工具叫作Kotlin REPL。稍后会解释REPL的含义,现在先打开它,看看能用它做些什么。如图1-14所示,在IntelliJ中,选择Tools → Kotlin → Kotlin REPL打开Kotlin REPL工具窗口。图1-14 打开Kotlin REPL工具窗口如图1-15所示,IntelliJ会在底部显示REPL窗口。图1-15 Kotlin REPL工具窗口你可以在里面输入代码,就像使用代码编辑器一样,但有一点不同:REPL不用编译整个项目,就能立即给出结果。在REPL中输入代码清单1-2所示的代码。

代码清单1-2 “Hello, Kotlin!”(REPL)println("Hello, Kotlin!")输入完成后,按Command-Return(Ctrl-Return)组合键在REPL中执行代码。如图1-16所示,很快,你就会在下面看到Hello, Kotlin!输出结果。图1-16 执行代码REPL是英文单词read(读取)、evaluate(求值)、print(输出)和loop(循环)的首字母缩写。整个运转流程如下:在提示符下输入一段代码,然后单击REPL左侧的绿色运行按钮或按Command-Return(Ctrl-Return)组合键提交。REPL读取代码,代码求值(运行代码),输出结果或副作用结果。运行完毕,REPL交回控制权,循环再次开始。Kotlin之旅已然启航!你在本章学了不少内容,已为进一步掌握Kotlin编程打下基础。下一章,你将开始探索Kotlin语言的细节,学习如何使用变量、常量以及各种数据类型。1.4 深入学习:为什么要用IntelliJ任何文本编辑器都可以用来编写Kotlin代码,不过,我们推荐使用IntelliJ,尤其是在学习这门语言的时候。如同凭借文字处理软件的拼写和语法检查功能,能更轻松地写出规范的文章一样,IntelliJ也更便于编写规范的Kotlin代码。这主要体现在以下几个方面。● 借助语法高亮、内容提示和代码自动补全等功能,你可以编写出

语法和语义正确的代码。● 借助应用程序运行时的断点调试和实时代码步进,你可以边运行

边调试代码。● 借助重构快捷命令(如重命名、导出常量)以及清理缩进和空行

的代码格式化功能,你可以重构现有代码。而且,由于Kotlin和IntelliJ都出自JetBrains公司,它们之间的集成设计更为细致周全,为用户带来了愉快的开发体验。另外,Android Studio基于IntelliJ开发,所以使用IntelliJ时学会的快捷操作和工具都可以直接运用。1.5 深入学习:面向JVMJVM本质上是个软件,它知道如何执行字节码指令。“面向JVM”就是把Kotlin代码编译或转译成Java字节码,以实现在JVM上运行,如图1-17所示。图1-17 编译和执行流程Windows平台也好,macOS平台也罢,它们都有各自的指令集。JVM搭起了字节码与不同软硬件平台间的桥梁,读取字节码并调用平台特有的与之匹配的指令。显然,不同软硬件平台有不同版本的JVM。这样一来,Kotlin开发人员就可以编写平台独立的程序代码,无论什么系统平台,都可实现一次编写,然后编译成字节码,在不同设备上执行。既然能转换成JVM可以执行的字节码,Kotlin也就是JVM语言。作为首门JVM语言,Java最为知名。在后来者,如Scala和Kotlin语言中,开发人员扬长避短,已消除了“前辈”Java的一些弊端。不过,Kotlin并未局限于JVM。本书撰写之际,Kotlin已能编译成JavaScript,甚至能脱离虚拟机层,直接编译成可以在Windows、Linux和macOS平台上运行的原生二进制代码。1.6 挑战练习:使用REPL研究Kotlin中的算数运算符本书很多章最后都配有挑战练习。请独立完成它们,以加深对Kotlin语言的理解,积累更多经验。使用REPL研究Kotlin中的+、-、*、/以及%这些算数运算符是如何工作的。例如,在REPL中,尝试输入(9+12)*2。结果符合预期吗?还想深入研究的话,可以看看https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.math/index.html网页列出的Kotlin标准库里的数学函数,在REPL里做做演练。例如,试试minOf (94, -99),求出最小值。第 2 章 变量、常量和类型本章,你将学习程序的基本组成元素:变量、常量以及Kotlin基本数据类型。变量和常量在应用程序中可用来储值和传递数据。类型则用来描述常量或变量中保存的是什么样的数据。2.1 数据类型变量和常量都有其指定的数据类型。类型描述常量或变量中保存的数据,告诉编译器该如何处理类型检查(type checking)。这种检查是Kotlin语言的一个特色,能避免变量和常量赋值出现类型不匹配错误。理论需要结合实践,下面我们就在第1章创建的Sandbox项目中添加一个文件。首先启动IntelliJ。既然IntelliJ默认会打开最近使用的项目,Sandbox项目应该会自动打开。如果没有,请在欢迎界面左边的最近使用的文件列表中找到并打开它,或者使用File → Open Recent → Sandbox菜单项打开。在项目工具窗口中右击src文件夹,添加一个新的项目文件。(没看到src文件夹的话,可能需要展开Sandbox项目文件夹。)选择New → Kotlin File/Class菜单项,输入文件名TypeIntro后确定,新文件随即会在编辑器中打开。第1章已说过,main函数是应用程序的入口点。使用IntelliJ编写这个函数有捷径:在TypeIntro.kt文件中,输入单词main,然后按Tab键。IntelliJ会自动为你添加该函数的基本结构,如代码清单2-1所示。

代码清单2-1 添加一个main函数(TypeIntro.kt)fun main(args: Array) {}2.2 声明变量假设你正在开发一个冒险游戏。游戏中,玩家可以探索一个互动世界。自然,你需要一个变量来保存玩家的经验值。在TypeIntro.kt文件中,创建一个名为experiencePoints的变量并赋值。

代码清单2-2 声明一个名为experiencePoints的变量(TypeIntro.kt)fun main(args: Array) { var experiencePoints: Int = 5 println(experiencePoints)}在上述代码中,你将一个Int类型的值赋给了experiencePoints变量。新增代码都起什么作用?我们来一探究竟。首先,使用var关键字定义一个变量。var后面跟着一个变量名,表示你想定义一个新变量。其次,使用: Int指定变量的类型。: Int表明,experiencePoints变量要存储的是整数。最后,使用赋值运算符(=)把右边的值(Int类型的实例值5)赋值给左边的experiencePoints变量。图2-1是experiencePoints变量定义的图解。图2-1 变量定义图解定义变量并赋值后,接下来使用println函数将变量值输出到控制台。单击main函数旁的运行按钮,选择Run ‘TypeIntroKt’ 运行程序。可以看到,输出到控制台的experiencePoints变量值是5。现在,尝试给experiencePoints变量赋值"thirty-two"。(删除线表明代码需删除。)

代码清单2-3 给 experiencePoints变量赋值"thirty-

two"(TypeIntro.kt)fun main(args: Array) { var experiencePoints: Int = 5 var experiencePoints: Int = "thirty-two" println(experiencePoints)}单击运行按钮再次运行main函数。这次,Kotlin编译器报错了:Error:(2, 33) Kotlin: Type mismatch: inferred type is String but Int was expected你可能已注意到,输入"thirty-two"时,它下面会出现红色波浪线。这是IntelliJ在警示代码有错。如图2-2所示,把光标悬停其上可以看到问题的具体描述。图2-2 类型不匹配Kotlin使用的是静态类型系统(static type system)。这表明,编译器会按类型标识代码定义,以确保编码有效。IntelliJ也会在代码输入时就开始检测,一旦发现变量类型和实例值类型不匹配,就立即指出。IntelliJ的这个特色功能叫静态类型检查,能在代码编译前发现代码问题。如代码清单2-4所示,为改正类型错误,需将experiencePoints变量值从"thirty-two"改回整数值5。

代码清单2-4 改正类型错误(TypeIntro.kt)fun main(args: Array) { var experiencePoints: Int = "thirty-two" var experiencePoints: Int = 5 println(experiencePoints)}即使已有初始值,也能给变量重新赋值。例如,在游戏中,如果玩家获得了更多经验值,就可以给experiencePoints变量赋新值。如代码清单2-5所示,给experiencePoints变量值加5。

代码清单2-5 experiencePoints变量值加5(TypeIntro.kt)fun main(args: Array) { var experiencePoints: Int = 5 experiencePoints + = 5 println(experiencePoints)}如上述代码所示,experiencePoints变量一开始赋值5,然后使用+=运算符在原基础上再加5。再次运行代码,可以看到,控制台输出了数值10。2.3 Kotlin的内置数据类型前面你已接触过String和Int类型的变量。Kotlin还有其他一些数据类型,可以接纳诸如true/false值、元素集合、键值对集合元素这样的数据。表2-1列出了Kotlin支持的一些常用数据类型。表2-1 常用内置类型类型描述示例Strin字符串"Estragon"g"happy meal"char单字符'X'Unicode character U+0041Booltrue/false值trueeanfalseInt整数"Estragon".length5Doub小数3.14le2.718List元素集合3, 1, 2, 4, 3"root beer", "club soda", "coke"Set无重复元素的"Larry", "Moe", "Curly"集合"Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"Map键值对集合"small" to 5.99, "medium" to 7.99, "large" to 10.99对这些数据类型不都熟悉的话,也不用担心,后面会陆续学到。第7章会介绍String类型,第8章会介绍数值类型,第10章和第11章会介绍合起来可称为集合类型的List、Set和Map。2.4 只读变量前面你已看到,变量可以重新赋值。但通常我们也需要使用不能改变值的变量。例如,在冒险游戏中,玩家名一旦设定就不能再改。Kotlin提供了一种语法来声明只读变量,也就是说,变量一旦赋值就不能更改。要声明可修改变量,使用var关键字。要声明只读变量,使用val关键字。日常口头交流时,可修改变量统称var,只读变量统称val。既然变量(variable)和只读变量(read-only variable)区分不明显,后续我们就沿用var和val这种叫法。var和val都被视为变量,所以我们继续使用“变量”来表示两组不同用处的变量。如代码清单2-6所示,为游戏玩家名添加只读变量定义,紧随经验值后打印出来。

代码清单2-6 添加名为playerName的只读变量(TypeIntro.kt)fun main(args: Array) { val playerName: String = "Estragon" var experiencePoints: Int = 5 experiencePoints + = 5 println(experiencePoints) println(playerName)}单击main函数旁边的运行按钮并选择Run ‘TypeIntroKt’ 运行程序。可以看到控制台打印出了经验值和玩家名。10Estragon如代码清单2-7所示,使用=赋值运算符,给playerName变量重新赋值,然后再次运行程序。

代码清单2-7 尝试修改playerName只读变量的值(TypeIntro.kt)fun main(args: Array) { val playerName: String = "Estragon" playerName = "Madrigal" var experiencePoints: Int = 5 experiencePoints + = 5 println(experiencePoints) println(playerName)}可以看到,编译器报错如下:Error:(3, 5) Kotlin: Val cannot be reassigned你试图修改只读变量的值,编译器当然要报错。记住,只读变量一旦赋值就不能再改。如代码清单2-8所示,删除只读变量再赋值语句以修正问题。

代码清单2-8 修正只读变量再赋值问题(TypeIntro.kt)fun main(args: Array) { val playerName: String = "Estragon" playerName = "Madrigal" var experiencePoints: Int = 5 experiencePoints + = 5 println(experiencePoints) println(playerName)}既然只读变量能防止不应该更改的变量被意外改动,任何时候,只要有需要,都推荐区分使用可变变量和只读变量。通过静态代码分析,IntelliJ能判定可变变量和只读变量是否使用恰当。如果一个不可变变量用了var关键字,IntelliJ会建议你改用val关键字。一般来说,我们推荐采纳IntelliJ的建议,除非你就是要给变量重新赋值。如果想看看IntelliJ是如何分析建议的,可把playerName定义为可变变量。

代码清单2-9 把playerName定义为可变变量(TypeIntro.kt)fun main(args: Array) { val playerName: String = "Estragon" var playerName: String = "Estragon" var experiencePoints: Int = 5 experiencePoints + = 5 println(experiencePoints) println(playerName)}playerName变量值不应再赋值,所以不需要也不应该使用var关键字定义。可以看到,IntelliJ已高亮了var关键字,如图2-3所示。将光标悬停其上,会看到IntelliJ给出的修改建议。图2-3 变量不应被修改和预期一样,IntelliJ建议以val关键字定义playerName变量。要采纳其建议,单击var关键字,然后按Option-Return(Alt-Enter)组合键。如图2-4所示,选择弹出菜单中的Make variable immutable选项。图2-4 定义不可变变量如图2-5所示,IntelliJ自动把var关键字改成了val。图2-5 不可变的playerName变量前面说过,任何时候,只要有必要,都建议使用val关键字。这样,IntelliJ就能在你不小心重新赋值的时候及时提醒。建议多多留意IntelliJ的代码改进建议,虽然不一定会用到,但多看看总没坏处。2.5 类型推断注意观察,你会发现playerName和experiencePoints变量的类型定义是灰色的。在IntelliJ中,某个元素呈灰色即表明该元素是多余的。如图2-6所示,将光标悬停在String类型定义上,IntelliJ会给出解释。图2-6 冗余类型信息IntelliJ所说的类型定义多余到底是什么意思呢?原来,Kotlin有个语言特性叫类型推断,对于已声明并赋值的变量,它允许你省略类型定义。既然String类型的playerName变量和Int类型的experiencePoints变量已赋值,Kotlin编译器就能据此推断出它们的数据类型。类似于IntelliJ能把可变变量(var)改为只读变量(val),IntelliJ也能自动帮你删除冗余的类型定义。单击playerName变量旁边的String类型定义(: String),然后按Option-Return (Alt-Enter)组合键。如图2-7所示,选择弹出菜单的Remove explicit type specification选项。图2-7 删除显式类型定义可以看到,String定义不见了。执行同样的操作,也删掉experiencePoints变量的: Int的定义。声明变量时,依赖类型推断也好,明确指定变量类型也好,编译器都会帮你记录类型定义。除非因为有歧义而必须手动管理,否则本书都会依靠类型推断来处理类型定义。这样做有助于编写简洁、易维护的代码。注意,IntelliJ会应要求显示任何变量的类型,包括那些使用类型推断的变量。如果你对一个变量的类型有疑问,可以单击变量名,并按Control-Shift-P组合键。IntelliJ会显示出变量的类型(见图2-8)。图2-8 查看类型信息2.6 编译时常量前面说过,可变变量可以重新赋值,而只读变量一旦赋值就无法更改。凡事无绝对,这是我们善意的谎言。事实上,你会在第12章看到,只读变量也有返回不同值的特例。真有数据要保证绝对只读的话,考虑使用编译时常量吧。编译时常量只能在函数(指包括main在内的所有函数)之外定义。这是因为,编译时常量必须在编译时(程序编译时)赋值,而main和其他函数都是在运行时(程序运行时)才调用,函数内的变量也是在那时赋值。编译时常量要在这些变量赋值前就已存在。因为使用复杂的数据类型可能会危害编译时的安全保障,所以编译时常量只能是一些常见的基本数据类型。第13章会介绍数据类型构建的相关知识。以下是编译时常量支持的基本数据类型:● String● Int● Double● Float● Long● Short● Byte● Char● Boolean在TypeIntro.kt文件中,如代码清单2-10所示,在main函数之上,使用const修饰符定义一个编译时常量。

代码清单2-10 定义一个编译时常量(TypeIntro.kt)const val MAX_EXPERIENCE: Int = 5000fun main(args: Array) { ...}和const修饰符一起使用的val告诉编译器,MAX_EXPERIENCE常量值绝对不会改变。这也就是说,无论如何,整数值5000要绝对保证不变。据此,编译器就知道该如何灵活处理代码优化。对常量名MAX_EXPERIENCE的书写格式感到好奇吗?编译器虽然没强制要求,但为突显编译时常量定义,我们倾向于使用这种字母全部大写、以下划线代替空格的格式。对于其他各种变量命名,你应该注意到了,我们依然遵循首字母小写的驼峰格式,以保证代码整洁易读。2.7 查看Kotlin字节码从第1章我们知道,Kotlin是Java之外的一种可选的开发语言,支持在执行Java字节码的JVM上运行。如果能查看Kotlin编译器生成的Java字节码,会对开发大有帮助。譬如,为分析Kotlin语言的某些功能在JVM上如何运作,本书中有好几个地方会让你查看Java字节码。懂Java的话,查看Kotlin代码的Java翻译版本将有助于深入理解Kotlin语言。不懂也没关系,可以看看Java翻译版代码和Kotlin代码有没有相似之处,就当作伪代码帮助学习Kotlin好了。什么编程语言都没学过?恭喜你选了Kotlin!稍后你会看到,相比Java,同样的逻辑用Kotlin表达起来更简洁。举个例子,你可能会好奇,定义变量时使用Kotlin类型推断,会对生成的JVM字节码有何影响。这很好办,使用Kotlin字节码工具吧。在TypeIntro.kt文件中,连按Shift键两次,打开Search Everywhere对话框。如图2-9所示,在搜索框中输入show kotlin,然后选择结果列表中的Show Kotlin Bytecode选项。图2-9 查看Kotlin字节码如图2-10所示,Kotlin字节码工具窗口会出现。(也可以经由Tools → Kotlin → Show Kotlin Bytecode菜单项打开字节码工具窗口。)图2-10 Kotlin字节码工具窗口不懂字节码这门“外语”?不用怕!在字节码工具窗口,单击左上角的Decompile按钮,就可以把字节码转译为你可能相对熟悉的Java语言。如图2-11所示,TypeIntro.decompiled.java文件,即Kotlin字节码的Java版本,会在一个新标签页中打开。图2-11 字节码的Java翻译版(图中的红色波浪线表明,Kotlin与Java交互过程中出现了偶发小问题,代码本身没有问题。)注意观察experiencePoints变量和playerName变量的定义:String playerName = "Estragon";int experiencePoints = 5;在Kotlin源码中,这两个变量的类型定义已省略,但在字节码中,还是看到了它们的显式类型定义。由此可见,字节码讲述了背后的故事,即Kotlin支持类型推断,所以不像Java那样,需要显式的变量类型定义。关于字节码的学习到此为止,后面的章节还会深入研究Java字节码。现在,可以关闭TypeIntro.decompiled.java文件(使用标签页中的X)和字节码工具窗口(使用右上角的)了。本章,你已学会使用可更改变量和只读变量存储基本数据,知道何时该用哪种变量,这主要取决于变量值是否能修改;了解了如何使用编译时常量定义不可变常量值;最后学会了使用Kotlin功能强大的类型推断,在声明变量时简化代码输入。后续学习时,你会反复运用这些知识和工具。下一章,我们将学习条件语句,看看如何利用它们编写出复杂的代码。2.8 深入学习:Kotlin中的Java基本数据类型Java有两类数据类型:引用类型与基本类型。引用类型有对应的源代码定义。基本类型不需要源码定义,由特殊关键字代表。Java引用类型名总是由大写字母开头,表明该类型有对应的源代码定义。下面是使用引用类型定义的experiencePoints变量:Integer experiencePoints = 5;作为对照,Java基本数据类型名以小写字母开头:int experiencePoints = 5;所有基本数据类型都有相对应的引用类型(但不是所有引用类型都有相对应的基本类型)。那该如何判断它们各自的使用场景呢?需要选用引用类型的一大原因是,某些Java语言特色功能只有引用类型才支持。例如,第17章要学习的泛型(generic)就不支持基本数据类型。此外,引用类型比基本类型更便于支持Java某些面向对象的特色功能。(第12章将介绍Kotlin面向对象编程及其面向对象的特色功能。)当然,基本数据类型也有其优点,而且性能表现比引用类型好。和Java不同,Kotlin只提供引用类型这一种数据类型。var experiencePoints: Int = 5Kotlin这样设计基于几大理由。首先,只有一种数据类型可选,你就不容易因选项多而选错,进而陷入编码困境。例如,定义了一个基本数据类型实例后,写着写着,猛然发现要用到只有引用类型才支持的泛型功能,怎么办?Kotlin通过只提供一种类型规避了此问题。也许熟悉Java的你会说:“但是基本数据类型的性能要好于引用类型啊!”没错,但我们再来看看前面字节码中experiencePoints变量的如下定义:int experiencePoints = 5;看到没有,基本数据类型又用回来了。为什么会这样?Kotlin不是只有引用数据类型吗?原来,只要有可能,出于更高性能的需要,Kotlin编译器会在Java字节码中改用基本数据类型。为了让你愉快地使用引用类型,Kotlin在后台改用了性能更佳的基本数据类型。假如你熟悉Java的八大基本数据类型,也能在Kotlin中分别找到它们的对应引用数据类型。2.9 挑战练习:定义hasSteed变量在冒险游戏中,玩家可能会拥有巨龙或人身牛头怪坐骑。定义一个名为hasSteed的变量做记录。给变量赋初值,以表明玩家现在还没坐骑。2.10 挑战练习:独角兽之角想象这样一幕冒险游戏场景。英雄Estragon走进一家叫作“独角兽之角”的小酒馆。酒馆老板问道:“需要牵马入厩吗?”“谢谢,”Estragon回答说,“我还没马呢,不过我有50个金币,给我来杯喝的吧。”“好极了!”酒馆老板说,“蜂蜜酒、葡萄酒,还有LaCroix气泡水,您

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载