在 Kotlin 中创建和使用变量

1. 准备工作

在手机应用中,有些部分会保持不变,而其他部分则会发生变化(或者是可变的)。

例如,在“设置”应用中,“网络和互联网”“已连接的设备”“应用”等类别名称会保持不变。

此“设置”应用屏幕截图显示了用于更改设备设置的不同菜单选项。屏幕上显示的菜单项包括:“网络和互联网”“已连接的设备”“应用”“通知”“电池”“存储”“提示音和振动”以及“显示”。

另一方面,如果您浏览新闻应用就会发现,其中显示的报道会经常变动。比方说,报道的名称、来源、发布时间和图片就会发生变化。

怎样编写代码,才能让内容随着时间而变化呢?每天、每小时甚至每分钟都会有新报道需要发布,您总不能在每次发布新的报道时都重写应用中的代码吧!

在本 Codelab 中,您将学习如何编写使用变量的代码,以便让程序的某些部分可以更改,而不必编写一套全新的指令。与上一个 Codelab 一样,您将会使用 Kotlin 园地。

构建内容

  • 使用变量的简短 Kotlin 程序。

学习内容

  • 如何定义变量并更新其值。
  • 如何从 Kotlin 的基本数据类型中为变量选择合适的数据类型。
  • 如何在代码中添加注释。

所需条件

  • 可连接到互联网的计算机和网络浏览器。

2. 变量和数据类型

在计算机编程中,“变量”这个概念表示单项数据的容器。您可以将“变量”想象成一个包含值的盒子,并且盒子上带有标签(也就是变量的名称)。您可以通过盒子名称来引用这个盒子,从而访问存储在其中的值。

此图显示了变量如何能像盒子存储物品那样存储数据。这里有一个标着“name”(名称)的盒子。盒子外面有一个标着“value”(值)的标签。有一个箭头正从值指向盒子,表示这个值会放入盒内。

如果能直接使用值,为什么还要将值存储在盒子里,然后通过盒子名称来引用这个盒子呢?这是因为,如果代码在所有指令中直接使用值,程序就只会在特定情况下运行。

让我们来打个比方,这样您就可以更轻松地了解变量为什么有用了。下面是给您最近会晤的人的一封信。

尊敬的 Lauren:

您好!很高兴今天能在办公室与您会晤。希望周五还能见到您。

祝您天天好心情!

这封信写得很好,但只适用于您遇到 Lauren 的这种特定情况。如果您发现自己需要多次撰写同样的信,只是因为对象不同,内容而略有变化,该怎么办?在这种情况下,建议您创建一个信函模板,并将可能变化的部分留空。

尊敬的____:

您好!很高兴今天能在_____与您会晤。希望____还能见到您。

祝您天天好心情!

您还可以指定每个空白区域所包含信息的类型,从而确保信函模板达到您的预期用途。

尊敬的 { name }:

您好!很高兴今天能在 {location} 与您会晤。希望 { date } 还能见到您。

祝您天天好心情!

从概念上讲,您可以采用类似的方式来构建应用;也就是,用占位符代替某些数据,同时让应用的其他部分保持不变。

此图示显示了一个新闻应用示例。屏幕内容以欢迎消息开头,其中的名称部分是用户实际名称的占位符。后面是一段内容为“Latest news for you”(为您推荐的最新新闻)的文本。无论应用中加载什么报道,这些文本都不会改变。然后,逐行列出了各篇新的报道,其中包括报道的图片、名称、日期和来源所对应的占位符。在报道列表的底部,有一个内容为“View more articles”(查看更多报道)的按钮。

在上面的新闻应用图示中,“Welcome”(欢迎)文本、“Latest news for you”(为您推荐的最新消息)标题以及“View more articles”(查看更多报道)按钮文本始终保持不变。与之相反,用户的名称和每篇报道的内容将会发生变化,因此可以使用变量存储每一条信息。

此图示并排显示了 3 个盒子。第一个盒子名为“name”(名称)。盒子旁边有一个内容为“Alex”的标签。有一个箭头从“Alex”指向盒子,表示“Alex”这个值会存储在名为“name”(名称)的盒子里。第二个盒子名为“article1Name”(报道 1 名称)。盒子旁边有一个内容为“New movie coming out”(即将上映的新片)的标签。有一个箭头从这个字符串指向第二个盒子。也就是说,“New movie coming out”(即将上映的新片)这个值会存储在名为“article1Name”(报道 1 名称)的盒子里。第三个盒子名为“article1Date”(报道 1 日期)。盒子旁边有一个内容为“June 9”(6 月 9 日)的标签。有一个箭头从“June 9”(6 月 9 日)指向第三个盒子。也就是说,“June 9”(6 月 9 日)这个值会存储在名为“article1Date”(报道 1 日期)的盒子里。

您没有必要在新闻应用中专门针对名叫 Alex 的用户或始终具有相同标题和发布日期的新闻报道编写适用的代码(或指令)。相反,您可以在编写代码时通过引用 namearticle1Namearticle1Date 等变量名称,增加应用的灵活性。如此一来,您的代码在通常情况下便足以适用许多不同的用例,例如不同的用户名称、不同的报道详情。

使用变量的示例应用

下面我们来看一个应用示例,了解其中可能使用变量的位置。

此 Google 地图应用屏幕截图显示了 Googleplex 这个营业地点的详细信息。这是一处企业园区,并且说明中指明这里是 Google 的全球总部。该营业地点获得的评分为 4.2 星(基于 9,831 条评价)。地址为 1600 Amphitheatre Pkwy, Mountain View, CA 94043。此屏幕显示了一个选项,供用户将这个营业地点保存到他们的列表中。

地图应用可能会显示各个营业地点(如餐馆或商家)的详情屏幕。上面的 Google 地图应用屏幕截图显示的就是 Google 公司总部(名为 Googleplex)的详细信息。您不妨想一想,哪几项数据会在该应用中存储为变量?

  • 营业地点的名称
  • 营业地点的星级
  • 营业地点的评价数量
  • 用户是否已保存此营业地点(即已为其添加书签)
  • 营业地点的地址
  • 营业地点的说明

通过更改存储在这些变量中的数据,您可以让地图应用保持足够的灵活性,使其也能显示其他营业地点的详细信息。

数据类型

在决定应用的哪些部分可变时,请务必指定可在这些变量中存储的数据类型。在 Kotlin 中,有一些常见的基本数据类型。下表逐行列明了各种不同的数据类型,并针对每种数据类型提供了可存储数据类型的说明和示例值。

Kotlin 数据类型

可包含的数据类型

字面量值示例

String

文本

"Add contact"
"Search"
"Sign in"

Int

整数

32
1293490
-59281

Double

小数

2.0
501.0292
-31723.99999

Float

小数(不如 Double 精确),数字末尾带有 fF

5.0f
-1630.209f
1.2940278F

Boolean

truefalse。当只有两个可能的值时,可使用此数据类型。请注意,truefalse 是 Kotlin 中的关键字。

true
false

现在,您已经了解了一些常见的 Kotlin 数据类型,那么对于在您之前所见营业地点详情页面中确定的各个变量,哪种数据类型会比较合适?

此 Google 地图应用屏幕截图显示了 Googleplex 这个营业地点的详细信息。这是一处企业园区,并且说明中指明这里是 Google 的全球总部。该营业地点获得的评分为 4.2 星(基于 9,831 条评价)。地址为 1600 Amphitheatre Pkwy, Mountain View, CA 94043。此屏幕显示了一个选项,供用户将这个营业地点保存到他们的列表中。

  • 营业地点的名称属于文本,可存储在数据类型为 String. 的变量中
  • 营业地点的星级属于小数(例如 4.2 颗星),可存储为 Double
  • 营业地点的评价数量属于整数,应存储为 Int
  • 涉及用户是否已保存此营业地点的数据只会有两个可能的值(即“已保存”或“未保存”),因此该数据存储为 Boolean,可用 truefalse 来代表各个状态。
  • 营业地点的地址属于文本,应为 String
  • 营业地点的说明也属于文本,应为 String

让我们再从下面的两个场景中练习一下。请确定在以下应用中使用的变量及其数据类型。

  1. 在用来观看视频的应用(如 YouTube 应用)中,有一个视频详情屏幕。变量可能会在何处使用?这些变量的数据类型是什么?

此屏幕截图显示了正在 YouTube 应用中播放的视频。该视频的名称为“Android Developers has reached 1M subscribers!”(Android 开发者订阅人数达到 100 万!)它发布在 YouTube 的 Android Developers 频道上。该视频的观看次数为 6,900 次,顶的次数为 541 次,评论数为 68 条。

正确答案不止一个,而在视频观看应用中,变量可用于以下几项数据:

  • 视频的名称 (String)
  • 频道的名称 (String)
  • 视频的观看次数 (Int)
  • 视频的顶的次数 (Int)
  • 视频的评论数 (Int)
  1. 在 Gmail 等电子邮件应用中,收件箱屏幕会列出最近收到的电子邮件。变量可能会在何处使用?这些变量的数据类型是什么?

此 Gmail 应用屏幕截图显示了用户收件箱中的邮件列表。收件箱中目前有 1 封邮件,发件人为 Mary Joe。该电子邮件的主题为“This weekend”(这个周末)。提供了一个用于为电子邮件加注星标的选项。

同样,正确答案不止一个。在电子邮件应用中,变量可用于以下几项数据:

  • 发件人的名称 (String)
  • 电子邮件的主题 (String)
  • 电子邮件是否已加星标 (Boolean)
  • 收件箱中新电子邮件的数量 (Int)

试试看

  1. 在手机上打开您喜爱的应用。
  2. 在应用的特定屏幕上找到您认为会使用变量的位置。
  3. 猜猜这些变量的数据类型。
  4. 在社交媒体上,提供应用的屏幕截图、说明您认为变量会用在何处,并使用 #AndroidBasics 标签来分享您的回答。

到目前为止,您在本 Codelab 中学得非常不错!请继续学习下一部分,详细了解如何在代码中使用变量和数据类型。

3. 定义和使用变量

定义与使用变量

您必须先在代码中定义变量,然后才能使用该变量。这与您在上一个 Codelab 中学到的关于在调用函数之前对其进行定义的做法类似。

定义变量时,您需要指定名称来对变量进行唯一标识,还需要指定数据类型来决定变量可以存储哪类数据。此外,您可以视需要提供将存储在变量中的初始值。

定义变量后,您便可以在程序中使用该变量。若要使用变量,请在代码中输入变量名称,指示 Kotlin 编译器在代码中的那个位置使用变量的值。

例如,为用户收件箱中的未读邮件数量定义一个变量。该变量的名称可以是 count。将一个值(例如 2)存储在变量中,代表用户收件箱中有 2 封未读邮件。(您可以选择其他数字来存入变量,但就本例而言,我们使用数字 2。)

这里有一个在标着“count”(数量)的盒子。盒子外面有一个标着“2”的标签。有一个箭头正从值指向盒子,表示这个值会放入盒内。

每当代码需要访问未读邮件的数量时,请在代码中输入 count。执行指令时,Kotlin 编译器就会在代码中找到对应的变量名称,并使用变量值来代替它。

从技术角度而言,我们可以用更具体的术语来描述这个过程:

“表达式”是存在值的一小段代码,可以由变量、函数调用等元素组成。在下例中,“表达式”由一个变量(即 count 变量)组成,并且值为 2

此图显示了一个表达式,旁边还有它的值。这里有一个“expression”(表达式)标签,下面写着“count”(计数);右侧有一个“value”(值)标签,下面写着“2”。

“求值”的意思是确定表达式的值。在本例中,表达式的求值结果为 2。编译器会对代码中的表达式求值,并在执行程序中的指令时使用这些值。

此图旨在显示表达式 count 的求值结果为 2。count 变量的名称 (count) 就显示在它的值 (2) 旁边。count 变量已用圆圈圈出,并有一个箭头从该 count 变量指向值 2。箭头下标有“evaluates to”(求值)的字样。

若要在 Kotlin 园地中观察此行为,请在下一部分运行该程序。

示例

  1. 在网络浏览器中打开 Kotlin 园地
  2. 将 Kotlin 园地中的现有代码替换为以下程序。

此程序会创建一个名为 count 且初始值为 2 的变量,并通过输出 count 变量的值来使用该值。如果您还不熟悉代码语法的各个方面,不用担心,后面几部分会对此做进一步说明。

fun main() {
    val count: Int = 2
    println(count)
}
  1. 运行程序,输出内容应如下所示:
2

变量声明

在运行的程序中,第二行代码如下:

val count: Int = 2

此语句会创建一个名为 count 且存储数字 2 的整数变量。

这里有一个在标着“count”(数量)的盒子。盒子外面有一个标着“2”的标签。有一个箭头正从值指向盒子,表示这个值会放入盒内。

若要通晓在 Kotlin 中声明变量的语法(或格式),您可能需要花费一些时间。不妨先通过下图了解变量应处位置的各个细节,以及空格和符号的位置。

此图显示了在 Kotlin 中声明变量的语法。变量声明以单词“val”开头,后跟一个空格。接下来是一个标着“name”(名称)的方框。名称框右侧是冒号。冒号后面先后跟着一个空格和一个标着“data type”(数据类型)的方框。之后,依次是一个空格、等号和另一个空格。最后是一个标着“initial value”(初始值)的方框。

在下面的 count 变量示例中,您可以看到以单词 val 开头的变量声明。该变量的名称为 count,数据类型为 Int,初始值为 2

此图显示了一行代码(内容为:val count: Int = 2)、几个指向代码各部分的箭头(用于指明这些部分各自的含义)、指向代码中“count”一词的“name”(名称)标签、指向代码中“Int”一词的“data type”(数据类型)标签,以及指向代码中数字 2 的“initial value”(初始值)标签。

接下来,让我们进一步了解变量声明的各个部分。

用于定义新变量的关键字

若要定义新变量,请以 Kotlin 关键字 val(表示值的意思)开头。然后,Kotlin 编译器就会知道这个语句中包含变量声明。

变量名称

和函数一样,您也要为变量命名。在变量声明中,变量名称跟在 val 关键字后面。

此图显示了在 Kotlin 中声明变量的语法。变量声明以单词“val”开头,后跟一个空格。接下来是一个标着“name”(名称)的方框。名称框使用绿色的边框和背景突出显示,以吸引大家注意变量声明中的这部分内容。名称框右侧是冒号。冒号后面先后跟着一个空格和一个标着“data type”(数据类型)的方框。之后,依次是一个空格、等号和另一个空格。最后是一个标着“initial value”(初始值)的方框。

您可以选择任意变量名称,但最佳做法是避免使用 Kotlin 关键字作为变量名称。

建议选择能够描述变量所存储数据的名称,以便让代码更易于理解。

与您在函数名称中学到的一样,变量名称应遵循驼峰式大小写惯例。变量名称中的第一个单词全部小写。如果名称中包含多个单词,则各个单词之间不应有空格,所有其他单词的首字母都应大写。

变量名称示例:

  • numberOfEmails
  • cityName
  • bookPublicationDate

在前面显示的代码示例中,count 就是变量名称。

val count: Int = 2

变量数据类型

在变量名称后,需依次添加冒号、空格和变量的数据类型。如前所述,StringIntDoubleFloat,Boolean 是一些基本的 Kotlin 数据类型。本课程后面的内容会对这些数据类型进行详细介绍。请务必准确拼写数据类型(如下所示),并以大写字母开头。

此图显示了在 Kotlin 中声明变量的语法。变量声明以单词“val”开头,后跟一个空格。接下来是一个标着“name”(名称)的方框。名称框右侧是冒号。冒号后面先后跟着一个空格和一个标着“data type”(数据类型)的方框。数据类型框使用绿色的边框和背景突出显示,以吸引大家注意变量声明中的这部分内容。在数据类型框的右侧,依次是一个空格、等号和另一个空格。最后是一个标着“initial value”(初始值)的方框。

count 变量示例中,Int 就是该变量的数据类型。

val count: Int = 2

赋值运算符

在变量声明中,等号 (=) 跟在数据类型之后。等号被称为赋值运算符。赋值运算符用于为变量赋值。换句话说,等号右侧的值会存储在等号左侧的变量中。

此图显示了一行代码(内容为:val count: Int = 2)、一个从 2(位于等号右侧)指向“count”一词(位于等号左侧)的箭头。这表示值 2 存储在 count 变量中。

变量初始值

变量值是存储在变量中的实际数据。

此图显示了在 Kotlin 中声明变量的语法。变量声明以单词“val”开头,后跟一个空格。接下来是一个标着“name”(名称)的方框。名称框右侧是冒号。冒号后面先后跟着一个空格和一个标着“data type”(数据类型)的方框。在数据类型框的右侧,依次是一个空格、等号和另一个空格。最后是一个标着“initial value”(初始值)的方框。初始值框使用绿色的边框和背景突出显示,以吸引大家注意变量声明中的这部分内容。

count 变量示例中,2 就是该变量的初始值。

val count: Int = 2

您还可能会听到“count 变量初始化为 2”的说法。这表示,在声明变量时,其中存储的第一个值是 2

初始值会因为变量声明的数据类型而异。

请参见下面的表格(您可能会发现,该表在 Codelab 前面的部分中曾出现过),第三列显示了可在各自对应类型的变量中存储的示例值。这些值称为“字面量”,因为它们是固定值或常量值(也就是保持不变的值)。举例来说,整数 32 的值始终是 32。相比之下,变量不是字面量,因为它的值可能会改变。您可能会听到以下根据各自类型来命名的字面量值:字符串字面量、整数字面量、布尔值字面量等。

Kotlin 数据类型

可包含的数据类型

字面量值示例

String

文本

"Add contact"
"Search"
"Sign in"

Int

整数

32
1293490
-59281

Double

小数

2.0
501.0292
-31723.99999

Float

小数(不如 Double 精确),数字末尾带有 fF

5.0f
-1630.209f
1.2940278F

Boolean

truefalse。当只有两个可能的值时,可使用此数据类型。请注意,truefalse 是 Kotlin 中的关键字。

true
false

请务必根据变量的数据类型提供适当的有效值。举例来说,您不能在 Int 类型的变量中存储字符串字面量(如 "Hello"),因为这会导致 Kotlin 编译器抛出错误。

使用变量

以下是您在 Kotlin 园地中运行的原始程序。到目前为止,您已了解第二行代码会创建一个名为 count 且值为 2 的新整数变量。

fun main() {
    val count: Int = 2
    println(count)
}

现在,让我们看看第三行代码。您将输出 count 变量:

println(count)

请注意,count 一词前后没有引号;它是变量名称,不是字符串字面量(如果是的话,则会用引号括起来)。运行程序时,Kotlin 编译器会依据 println() 指令,对括号内的表达式(即 count)进行求值。由于表达式的求值结果为 2,因此系统会将 2 作为输入来调用 println() 方法:println(2)

因此,程序的输出内容如下:

2

输出数字本身并不是很有用。如果在输出内容中输出更详细的消息来解释 2 所代表的含义,会更为实用。

字符串模板

以下是在输出内容中显示的更实用消息:

You have 2 unread messages.

您只需按照以下步骤操作,即可让程序输出更实用的消息。

  1. 在 Kotlin 园地中,使用以下代码更新您的程序。向 println() 调用传入包含 count 变量名称的字符串字面量。别忘了用引号括住该文本。请注意,目前您还不会获得预期结果。我们将在后续步骤中解决该问题。
fun main() {
    val count: Int = 2
    println("You have count unread messages.")
}
  1. 运行程序,输出内容应如下所示:
You have count unread messages.

这句话不知所云!您应该在消息中显示 count 变量的值,而不是变量名称。

  1. count 变量前面添加美元符号 $(即 "You have $count unread messages.")来修正您的程序。这是一个字符串模板,因为它包含模板表达式,在本例中为 $count。模板表达式是一种会将求得的值替换到字符串中的表达式。在本例中,模板表达式 $count 的求值结果为 2,并且 2 会替换到表达式所处的字符串中。
fun main() {
    val count: Int = 2
    println("You have $count unread messages.")
}
  1. 运行程序后,您将会获得所需的输出内容:
You have 2 unread messages.

对于用户来说,这句话更容易理解!

  1. 现在,将 count 变量的初始值更改为其他整数字面量(例如,您可以选择数字 10),并让程序中的其余代码保持不变。
fun main() {
    val count: Int = 10
    println("You have $count unread messages.")
}
  1. 运行程序。请注意,输出内容会相应地改变,您甚至不需要更改程序中的 println() 语句。
You have 10 unread messages.

看到字符串模板是多么有用了吧?您在代码 ("You have $count unread messages.") 中只编写了一次字符串模板。即使更改 count 变量的初始值,println() 语句还是会正常发挥作用。现在,您的代码更加灵活啦!

为了进一步加深对这一点的认识,接下来比较以下两个程序。第一个程序(如下所示)使用了字符串字面量,在此字符串中直接包含未读邮件的确切数量。在这种情况下,只有当用户收到 10 封未读邮件时,此程序才能正常运行。

fun main() {
    println("You have 10 unread messages.")
}

第二个程序(如下所示)使用了变量和字符串模板,让代码可以适应更多的场景。因此,第二个程序更加灵活!

fun main() {
    val count: Int = 10
    println("You have $count unread messages.")
}

类型推断

下面的提示可帮助您减少在声明变量时编写的代码。

利用类型推断,当 Kotlin 编译器可以推断(或确定)变量应属的数据类型时,您不必在代码中写入确切类型。这意味着,如果您为变量提供了初始值,就可以在变量声明中省略数据类型。Kotlin 编译器会查看初始值的数据类型,并假定变量会存储该类型的数据。

以下是使用类型推断来声明变量的语法:

此图显示了使用类型推断在 Kotlin 中声明变量的语法。变量声明以单词“val”开头,后跟一个空格。接下来是一个标着“name”(名称)的方框。在名称框的右侧,依次是一个空格、等号和另一个空格。最后是一个标着“initial value”(初始值)的方框。

返回去看看 count 示例,该程序最初包含以下这行代码:

val count: Int = 2

不过,您还可以按如下方式编写这行代码。请注意,冒号 (:) 和 Int 数据类型已被省略。使用更新后的语法,您不但可以减少需要输入的单词,而且还能取得与创建名为 count 且值为 2Int 变量相同的结果。

val count = 2

Kotlin 编译器知道您想将 2(整数)存储到变量 count 中,因此可以推断出 count 变量的类型为 Int。是不是很省事呀?下面这个示例就展示了如何编写更简洁的 Kotlin 代码!

虽然此示例只讨论了 Int 类型的变量,但类型推断的概念适用于 Kotlin 中所有的数据类型。

整数的基本数学运算

值为 2Int 变量与值为 "2"String 变量有何区别?如果都看输出内容的话,两者一样。

将整数存储为 Int(而不是 String)的优势在于,您可以使用 Int 变量执行数学运算,例如加法、减法、除法和乘法(有关其他数学运算,请参见运算符)。例如,可将两个整数变量相加,得出它们的总和。当然,在某些情况下,可以将整数存储为字符串;但本部分的目的是为了向您展示可以使用 Int 变量来做些什么。

  1. 返回 Kotlin 园地,移除代码编辑器中的所有代码。
  2. 创建一个新程序,在其中为收件箱中未读电子邮件的数量定义一个整数变量,并为其提供初始值(例如 5)。您可以根据需要选择其他数字。为收件箱中的已读电子邮件数量定义第二个整数变量,并为其提供初始值(例如 100)。您可以根据需要选择其他数字。接着,将两个整数相加后,输出收件箱中的邮件总数。
fun main() {
    val unreadCount = 5
    val readCount = 100
    println("You have ${unreadCount + readCount} total messages in your inbox.")
}
  1. 运行程序,它应该会显示收件箱中的邮件总数:
You have 105 total messages in your inbox.

在学习字符串模板时,我们了解到,可以在单个变量名称前加上 $ 符号。但是,如果您使用更复杂的表达式,就必须用大括号将该表达式括起来,并在大括号前添加 $ 符号:${unreadCount + readCount}。用大括号括起来的表达式(即 unreadCount + readCount)的求值结果为 105。然后,105 这个值会替换到字符串字面量中。

此图显示了一个表达式,旁边还有它的值。有一个“expression”(表达式)标签,它的下方写着“unreadCount + readCount”。右侧有一个“value”(值)标签,它的下方写着“105”。

  1. 若要进一步了解这个主题,请创建具有不同名称和不同初始值的变量,然后使用模板表达式来输出信息。

例如,修改您的程序以输出以下内容:

100 photos
10 photos deleted
90 photos left

您可以按照下面这种方式编写程序,也可以采用其他正确方式进行编写!

fun main() {
    val numberOfPhotos = 100
    val photosDeleted = 10
    println("$numberOfPhotos photos")
    println("$photosDeleted photos deleted")
    println("${numberOfPhotos - photosDeleted} photos left")
}

4. 更新变量

应用在运行时,可能需要更新变量的值。例如,在购物应用中,如果用户向购物车添加商品,购物车总金额就会增加。

让我们将购物用例简化成一个简单的程序。下面的逻辑是用人类语言(而非 Kotlin)编写的,属于伪代码,因为它只描述了代码编写方式的要点,并未包含代码的所有细节。

在程序的 main 函数中:

  • 创建一个从 0 值开始的整数 cartTotal 变量。
  • 用户在购物车中添加了一件 20 元的毛衣。
  • cartTotal 变量更新为 20(即购物车中商品的当前费用)。
  • 输出购物车中商品的总费用(即 cartTotal 变量)。

为了进一步简化代码,您无需针对客户向购物车添加商品这种情况编写代码。(在后面的单元中,我们将会学习程序如何对用户输入做出响应。)请将重心放在创建、更新和输出 cartTotal 变量的部分。

  1. 将 Kotlin 园地中的现有代码替换为以下程序。程序的第 2 行代码会将 cartTotal 变量的初始值设为 0。由于已经提供初始值,通过类型推断即可获知 Int 数据类型,因此不必再指定该数据类型。程序的第 3 行代码会尝试使用赋值运算符 (=) 将 cartTotal 变量更新为 20。程序的第 4 行代码会使用字符串模板来输出 cartTotal 变量。
fun main() {
    val cartTotal = 0
    cartTotal = 20
    println("Total: $cartTotal")
}
  1. 运行程序,系统会抛出编译错误。
  2. 注意该错误会指明无法对 val 重新赋值。错在程序的第三行,该行代码会尝试将 cartTotal 变量的值更改为 20. 因为已经向 val cartTotal 赋予初始值 (0),所以不能再为该变量重新赋予其他值 (20)。
Val cannot be reassigned

如果您需要更新变量的值,请使用 Kotlin 关键字 var(而不是 val)声明该变量。

  • val 关键字 - 预计变量值不会变化时使用。
  • var 关键字 - 预计变量值会发生变化时使用。

如果使用 val,变量只读,也就是说您只能读取或访问变量的值。值一经设置,便无法再编辑或修改。如果使用 var,变量可变,也就是说值可被更改或调整,可以进行转变。

若要记住区别,不妨将 val 视为固定值,将 var 视为变量。在 Kotlin 中,建议尽量使用 val 关键字,而不是 var 关键字。

  1. 在程序第 2 行代码中,更新对 cartTotal 的变量声明,以使用 var,而不是 val。该代码如下所示:
fun main() {
    var cartTotal = 0
    cartTotal = 20
    println("Total: $cartTotal")
}
  1. 注意程序中第 3 行代码的语法(用于更新变量)。
cartTotal = 20

使用赋值运算符 (=) 为现有变量 (cartTotal) 赋予新值 (20)。由于该变量已定义,因此您无需再次使用 var 关键字。

此图显示了一行代码(内容为:cartTotal = 20)、一个从 20(位于等号右侧)指向“cartTotal”一词(位于等号左侧)的箭头。这表示值 20 存储在 cartTotal 变量中。

以盒子为喻,想象 20 这个值是存储在标着 cartTotal(购物车总金额)的盒子里。

这里有一个在标着“cartTotal”(购物车总金额)的盒子。盒子外面有一个标着“20”的标签。有一个箭头正从值指向盒子,表示这个值会放入盒内。

下图显示了更新变量的一般语法,相关变量已在前一行代码中声明。以要更新的变量的名称为语句开头。之后,依次添加一个空格、等号和另一个空格。最后,写入变量的更新值。

此图显示了在 Kotlin 中更新变量的语法。这行代码以标着“name”(名称)的方框开头。在名称框的右侧,依次是一个空格、等号和另一个空格。最后是一个标着“updated value”(更新值)的方框。

  1. 运行程序,代码应该能成功编译。输出内容应如下所示:
Total: 20
  1. 若要了解变量值在程序运行期间的变化情况,请在最初声明 cartTotal 变量后输出该变量。更改后的代码如下所示。第 3 行添加了新的 println() 语句。代码的第 4 行还添加了一个空行。空行不会对编译器理解代码的方式产生任何影响。通过添加空行来隔开相关代码块,可让代码更易于阅读。
fun main() {
    var cartTotal = 0
    println("Total: $cartTotal")

    cartTotal = 20
    println("Total: $cartTotal")
}
  1. 再次运行程序,输出内容应如下所示:
Total: 0
Total: 20

您可以看到,购物车总金额最初为 0,之后更新为 20。您成功更新变量啦!之所以成功,是因为您将 cartTotal 从只读变量(使用 val)改为了可变变量(使用 var)。

请注意,只有在预计值会发生变化时,才应使用 var 声明变量;否则,应默认使用 val 声明变量。这样做是为了提高代码的安全性。使用 val 可防止变量在程序中意外更新。为 val 赋值后,该值就会一直保持不变。

增量运算符和减量运算符

现在您已经知道,必须将变量声明为 var,才能更新其值。让我们将这个知识应用到我们之前使用的电子邮件示例中。

  1. 使用以下程序替换 Kotlin 园地中的代码:
fun main() {
    val count: Int = 10
    println("You have $count unread messages.")
}
  1. 运行程序,输出内容应如下所示:
You have 10 unread messages.
  1. val 关键字替换为 var 关键字,使 count 变量成为可变变量。运行程序后,输出内容应该没有变化。
fun main() {
    var count: Int = 10
    println("You have $count unread messages.")
}
  1. 不过,现在您可以将 count 更新为其他值。例如,当用户在收件箱中收到一封新的电子邮件时,您可以将 count 加 1。(您无需针对收到电子邮件这种情况编写代码。我们会在后面的单元中,讨论从互联网获取数据这个更高级的主题。)此刻我们只需知道,以下这行代码会让 count 变量加 1
count = count + 1

等号右侧的表达式 count + 1 的求值结果为 11,因为 count 的当前值为 10(程序的第 2 行),而 10 + 1 等于 11。然后,使用赋值运算符向 count 变量赋予 11 这个值(也就是让值存储在该变量中)。

此图显示了一行代码,内容为:count = count + 1。“count + 1”表达式周围画有一个圆圈。有一个箭头从等号右侧带圆圈的表达式指向等号左侧“count”一词。这表示“count + 1”表达式的值存储在 count 变量中。

将下面这行代码添加到程序中 main() 函数底部。您的代码应如下所示:

fun main() {
    var count = 10
    println("You have $count unread messages.")
    count = count + 1
}

如果您现在运行程序,输出内容会与之前一样,因为您在更新 count 变量后未添加任何代码。

  1. 添加另一个输出语句,用于在变量更新后输出未读邮件的数量。
fun main() {
    var count = 10
    println("You have $count unread messages.")
    count = count + 1
    println("You have $count unread messages.")
}
  1. 运行程序。第二条消息应该会显示更新后的 count(即 11 封邮件)。
You have 10 unread messages.
You have 11 unread messages.
  1. 如果您想让变量加 1,可以使用由两个加号组成的增量运算符 (++) 来简化代码。只需直接在变量名称后面使用这些符号,便可指示编译器将变量的当前值加 1,然后将新值存储在变量中。下面两行代码是等效的,但使用 ++ 增量运算符可减少输入。
count = count + 1
count++

修改您的代码,然后运行程序。变量名称和增量运算符之间不应有空格。

fun main() {
    var count = 10
    println("You have $count unread messages.")
    count++
    println("You have $count unread messages.")
}
  1. 运行程序。虽然输出内容没变,但现在您了解了一个新的运算符!
You have 10 unread messages.
You have 11 unread messages.
  1. 接下来,修改程序的第 4 行,在 count 变量名称后使用减量运算符 (--)。减量运算符由两个减号组成。您可以在变量名称后面放置减量运算符,指示编译器将变量的值减 1,然后将新值存储在变量中。
fun main() {
    var count = 10
    println("You have $count unread messages.")
    count--
    println("You have $count unread messages.")
}
  1. 运行程序,输出内容应如下所示:
You have 10 unread messages.
You have 9 unread messages.

在这一部分中,我们学习了如何使用增量运算符 (++) 和减量运算符 (--) 更新可变变量。更具体地说,count++ 等同于 count = count + 1count-- 等同于 count = count - 1

5. 探索其他数据类型

在本 Codelab 前面的部分中,我们介绍了一些常见的基本数据类型(StringIntDoubleBoolean);刚才也让您使用了 Int 数据类型。现在,让我们来看看其他数据类型。

Kotlin 数据类型

可包含的数据类型

String

文本

Int

整数

Double

小数

Boolean

truefalse(只有两个可能的值)

不妨在 Kotlin 园地中试试这些程序,看看会输出什么内容。

Double

如果您需要一个可以存储小数值的变量,请使用 Double 变量。若要了解其有效范围,请参阅这个表格,看看该变量可以存储的小数位数示例。

假设您要导航到某个目的地,由于沿途需要停靠,因此您的行程被拆分成三个单独的部分。此程序会显示到达目的地所需的总距离。

  1. 在 Kotlin 园地中输入以下代码。您能明白每行代码的具体含义吗?
fun main() {
    val trip1: Double = 3.20
    val trip2: Double = 4.10
    val trip3: Double = 1.72
    val totalTripLength: Double = 0.0
    println("$totalTripLength miles left to destination")
}

在上述代码中,声明了三个名为 trip1trip2trip3 的变量,用以指明每一段行程的距离。所有这些变量存储的都是小数值,因此它们属于 Double 变量。之所以使用 val 来声明每个变量,是因为它们的值在程序运行过程中不会改变。该程序还会创建第四个变量(名为 totalTripLength),其当前初始值为 0.0。程序的最后一行会输出包含 totalTripLength 值的消息。

  1. 修正代码,使 totalTripLength 变量是所有三段行程长度的总和。
val totalTripLength: Double = trip1 + trip2 + trip3

等号右侧表达式的求值结果为 9.02,因为 3.20 + 4.10 + 1.72 等于 9.029.02 这个值会存储在 totalTripLength 变量中。

此图显示了一行代码,内容为:val totalTripLength: Double = trip1 + trip2 + trip3。“trip1 + trip2 + trip3”表达式周围画有一个圆圈。有一个箭头从等号右侧带圆圈的表达式指向等号左侧“totalTripLength”一词。这表示“trip1 + trip2 + trip3”表达式的值存储在 totalTripLength 变量中。

整个程序应如以下代码所示:

fun main() {
    val trip1: Double = 3.20
    val trip2: Double = 4.10
    val trip3: Double = 1.72
    val totalTripLength: Double = trip1 + trip2 + trip3
    println("$totalTripLength miles left to destination")
}
  1. 运行程序,输出内容应如下所示:
9.02 miles left to destination
  1. 修正代码,从变量声明中移除由于类型推断而变为多余的 Double 数据类型。Kotlin 编译器可以根据初始值(提供的是小数)推断出这些变量属于 Double 数据类型。
fun main() {
    val trip1 = 3.20
    val trip2 = 4.10
    val trip3 = 1.72
    val totalTripLength = trip1 + trip2 + trip3
    println("$totalTripLength miles left to destination")
}
  1. 再次运行您的代码,确保该代码仍然可以编译。输出内容应该一样,但是现在代码变得更简单了!

String

如果您需要一个可以存储文本的变量,请使用 String 变量。请务必用引号引住 String 字面量值(如 "Hello Kotlin"),但不要用引号引住 IntDouble 字面量值。

  1. 复制此程序并将其粘贴到 Kotlin 园地中。
fun main() {
    val nextMeeting = "Next meeting is:"
    val date = "January 1"
    val reminder = nextMeeting + date
    println(reminder)
}

请注意,在上述代码中,声明了 nextMeetingdate 这两个 String 变量;然后,声明了名为 reminder 的第三个 String 变量,该变量被设为等于 nextMeeting 变量加 date 变量。

您可以使用 + 号将两个字符串加在一起(这种做法称为“串联”)。当两个字符串前后组合起来后,表达式 nextMeeting + date 的结果即为 "Next meeting is:January 1",如下图所示。

此图旨在显示表达式“nextMeeting + date”的求值结果为“Next meeting is:January 1”。表达式“nextMeeting + date”已用圆圈圈出,并有一个箭头从该表达式指向值“Next meeting is:January 1”。箭头下标有“evaluates to”(求值)的字样。

然后,在程序第 4 行中,使用赋值运算符将值 "Next meeting is:January 1" 存储到 reminder 变量中。

  1. 运行程序,输出内容应如下所示:
Next meeting is:January 1

如果您将两个字符串串联在一起,这两个字符串之间不会添加任何额外的空格。如果您想让输出字符串中的冒号后面有空格,则需要在其中一个字符串中添加空格。

  1. 更新 nextMeeting 变量,在字符串末尾右引号前面添加一个额外的空格(或者,您也可以在 date 变量的开头添加了一个额外的空格)。程序应如下所示:
fun main() {
    val nextMeeting = "Next meeting is: "
    val date = "January 1"
    val reminder = nextMeeting + date
    println(reminder)
}
  1. 再次运行程序。现在,输出消息中的冒号后面应该会显示一个空格。
Next meeting is: January 1
  1. 修改代码,将另一段文本串联(或添加)到要存储在 reminder 变量中的表达式后。

使用 + 号将字符串字面量 "at work" 添加到 reminder 字符串的末尾。

  1. 运行程序。

输出内容应如下所示:

Next meeting is: January 1 at work

以下代码显示了实现该行为的一种方法。

fun main() {
    val nextMeeting = "Next meeting is: "
    val date = "January 1"
    val reminder = nextMeeting + date + " at work"
    println(reminder)
}

请注意,不要用引号将 nextMeetingdate 括起来,因为它们是现有字符串变量的名称(各自值都是用引号括起来的文本)。与之相反,字面量 "at work" 之前未在任何变量中定义,因此请用引号将这个文本引起来,以便让编译器知道这是一个应串联到其他字符串上的字符串。

从技术层面来讲,您可以声明包含完整文本的单个 String 变量(而不是使用单独的变量)来实现相同输出。不过,本练习的目的是为了说明如何声明和操纵 String 变量,特别是如何串联单独的字符串。

  1. 读取包含字符串的代码时,您可能会遇到转义序列。转义序列是指前面带有反斜杠符号(\,也称为转义反斜杠)的字符。

在下面的例子中,字符串字面量中出现了 \"。请复制此代码并将其粘贴到 Kotlin 园地中。

fun main() {
    println("Say \"hello\"")
}

您之前已学习使用英文双引号将字符串字面量引起来。但是,如果您想在字符串中使用 " 符号,该怎么办?在这种情况下,您需要在字符串中的英文引号前面添加反斜杠符号,表示为 \"。请注意,整个字符串应仍使用英文双引号引起来。

  1. 运行该程序来查看输出,其中内容应如下所示:
Say "hello"

在输出中,hello 会使用英文双引号引起来,因为我们在 println() 语句中 hello 的前后都添加了 \"

如需了解 Kotlin 支持的其他转义序列,请参阅有关转义序列的文档页面。例如,如果要在字符串中另起一行,请在字符 n 前面使用 \ 符号,表示为 \n

现在,您已经学习了如何串联字符串,以及如何在字符串中使用转义序列。让我们继续学习本 Codelab 涵盖的最后一个数据类型。

Boolean

当变量只有两个可能的值(用 truefalse 表示)时,Boolean 数据类型会非常有用。

例如,指示设备的飞行模式是处于开启还是关闭状态的变量,或者指示应用的通知功能是处于启用还是停用状态的变量。

  1. 在 Kotlin 园地中输入以下代码。此程序的第 2 行代码会声明一个名为 notificationsEnabledBoolean 变量,并提供初始化值 true。从技术上讲,可在声明中省略 : Boolean。因此,如果需要的话,您可以移除该变量。程序的第 3 行代码会输出 notificationsEnabled 变量的值。
fun main() {
    val notificationsEnabled: Boolean = true
    println(notificationsEnabled)
}

运行程序,输出内容应如下所示:

true
  1. 在程序的第 2 行代码中,将 Boolean 的初始值更改为 false。
fun main() {
    val notificationsEnabled: Boolean = false
    println(notificationsEnabled)
}

运行程序,输出内容应如下所示:

false
  1. 其他数据类型可以串联到 Strings 上。例如,您可以将 Booleans 串联到 Strings 上。请使用 + 号将 notificationsEnabled 布尔值变量的值串联(或附加)到 "Are notifications enabled? " 字符串的末尾。
fun main() {
    val notificationsEnabled: Boolean = false
    println("Are notifications enabled? " + notificationsEnabled)
}

运行程序来查看串联的结果。程序应输出以下内容:

Are notifications enabled? false

您可以看到,Boolean 变量的值能设为 truefalse。有了 Boolean 变量,您就可以用代码表示更加复杂的场景。在 Boolean 变量的值为 true 时,执行一组指令;在 Boolean 变量的值为 false 时,跳过这些指令。在后续的 Codelab 中,我们会对 Booleans 进行详细说明。

6. 编码规范

在上一个 Codelab 中,我们为您介绍了 Kotlin 样式指南,这是 Google 推荐使用并且其他专业开发者也在遵循的一种 Android 代码统一编写方式。

对于所学的新主题,您还需遵循其他一些格式设置和编码规范:

  • 变量名称应采用驼峰式大小写形式,并以小写字母开头。
  • 在变量声明中指定数据类型时,应在冒号后面添加一个空格。

此图显示了一行代码,内容为:val discount: Double = .20。有一个箭头在指向冒号和 Double 数据类型之间的那个空格,上面是一个内容为“space”的标签。

  • 赋值运算符 (=)、加号 (+)、减号 (-)、乘号 (*)、除号 (/) 等运算符的前后应有空格。

此图显示了一行代码,内容为:var pet = "bird"。有几个箭头在指向等号前后的那些空格,上面是一个内容为“space”的标签。

此图显示了一行代码,内容为:val sum = 1 + 2。有几个箭头在指向加号前后的那些空格,上面是一个内容为“space”的标签。

7. 在代码中添加注释

编写代码时,另一个建议遵循的较好做法是添加注释来说明代码的用途。这样做可帮助读者更轻松地理解代码。您可以使用两个正斜杠符号 (//) 来指明将相应行中该符号后面的剩余文本视为注释,而不要解释为代码。通常的做法是在两个正斜杠符号后添加一个空格。

// This is a comment.

您也可以在一行代码的中间位置插入注释。在下面的示例中,height = 1 是正常的编码语句。// 之后的所有内容(即 Assume the height is 1 to start with)都会被解释为注释,而不会被视为代码。

height = 1 // Assume the height is 1 to start with.

如果您想用一行超过 100 个字符的长注释来详细说明代码,不妨使用多行注释。具体方法为:使用由正斜杠 (/) 和星号 (*) 组成的 /* 来作为多行注释的开头,在注释的每个新行开头添加一个星号,最后使用由星号和正斜杠符号组成的 */ 作为结尾。

/*
 * This is a very long comment that can
 * take up multiple lines.
 */

以下程序包含描述代码行为的单行注释和多行注释:

/**
 * This program displays the number of messages
 * in the user's inbox.
 */
fun main() {
    // Create a variable for the number of unread messages.
    var count = 10
    println("You have $count unread messages.")

    // Decrease the number of messages by 1.
    count--
    println("You have $count unread messages.")
}

如前所述,您可以在代码中添加空行来对相关语句进行分组,让代码更易于阅读。

  1. 在之前使用的代码段中添加一些注释。
  2. 运行程序,确认行为未发生变化(注释不应该影响输出)。

8. 总结

做得很好!您已经了解 Kotlin 中的变量、变量为什么在编程中大有用处,以及如何创建、更新和使用变量。您尝试了 Kotlin 中不同的基本数据类型(包括 IntDoubleStringBoolean 数据类型),同时还了解了 valvar 关键字之间的区别。

在成为开发者的旅程中,所有这些概念都是您前进道路上的重要基石。

期待与您相会于下一个 Codelab!

总结要点

  • 变量是存储单项数据的容器。
  • 必须先声明变量,然后才能使用它。
  • val 关键字用于定义只读变量;其中的变量一旦赋值,就不能再更改。
  • var 关键字用于定义可变变量。
  • 在 Kotlin 中,建议您尽可能使用 val,而不是 var
  • 如需声明变量,请以 valvar 关键字开头,然后指定变量名称、数据类型和初始值。例如:val count: Int = 2
  • 使用类型推断时,如果提供了初始值,则可以在变量声明中省略数据类型。
  • 一些常见的基本 Kotlin 数据类型包括:IntStringBooleanFloatDouble
  • 在声明或更新变量时,请使用赋值运算符 (=) 为变量赋值。
  • 只能更新通过 var 声明为可变变量的变量。
  • 增量运算符 (++) 用于为整数变量的值加 1,减量运算符 (--) 用于为整数变量的值减 1。
  • + 符号用于串联各个字符串,也可用于将其他数据类型的变量(如 IntBoolean)串联到 Strings

了解详情