02. Kotlin 变量、常量和类型

数据类型

数值类型

在 Kotlin,一切都是一个对象,你可以调用任何变量的成员函数和属性。有些类型可以有一个特殊的内部表示——例如,数字、字符和布尔值可以在运行时表示为基本值——但对用户来说,它们看起来像普通类。

Kotlin 这样设计基于几大理由。首先,只有一种数据类型可选,你就不容易因选项多而选错, 进而陷入编码困境。例如,定义了一个基本数据类型实例后,写着写着,猛然发现要用到只有引 用类型才支持的泛型功能,怎么办?Kotlin 通过只提供一种类型规避了此问题。也许熟悉 Java 的你会说:“但是基本数据类型的性能要好于引用类型啊!”。为了让你愉快地使用引用类型,Kotlin 编译器会根据不同的场景将其编译成为 Java 中的基本类型数据还是包装类对象。假如你熟悉 Java 的八大基本数据类型,也能在 Kotlin 中分别找到它们的对应引用数据类型。

  • 整数类型:Byte、Short、Int 和 Long,Int 是默认类型。
  • 浮点类型:Float 和 Double,Double 是默认类型。
  • 字符类型:Char。
  • 布尔类型:Boolean

整数类型

Kotlin 提供了一组表示数字的内置类型。对于整数,有四种不同大小的类型(Byte、Short、Int 和 Long)。

当初始化没有显式类型规范的变量时,编译器会自动推断出具有足以表示该值的最小范围的类型。如果不超过 Int 的范围,则该类型为 Int。如果超过,则类型为 Long。若要显式指定 Long 值,请将后缀 L 附加到该值。显式类型规范触发编译器检查值是否不超过指定类型的范围。

val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1

除了整数类型之外,Kotlin 还为无符号整数提供了以下类型:

UByte: an unsigned 8-bit integer, ranges from 0 to 255
UShort: an unsigned 16-bit integer, ranges from 0 to 65535
UInt: an unsigned 32-bit integer, ranges from 0 to 2^32 - 1
ULong: an unsigned 64-bit integer, ranges from 0 to 2^64 - 1

未签名类型支持其对应的已签名类型的大多数操作。

浮点类型

对于实数,Kotlin 提供了遵循 IEEE 754 标准的浮点类型 Float 和 Double。Float 反映 IEEE 754 的单精度,而 Double 反映的是双精度。

可以使用具有小数部分的数字初始化 Double 和 Float 变量。它与整数部分之间用句点(.)隔开对于用小数初始化的变量,编译器推断出 Double 类型:

val pi = 3.14 // Double
// val one: Double = 1 // Error: type mismatch
val oneDouble = 1.0 // Double

若要显式指定值的 Float 类型,请添加后缀 f 或 F。如果该值包含超过6-7个小数位,它将被四舍五入:

val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817

字符类型

用\转义字符。是字符还是有特别意义的标记,编译器通过转义字符 就能区分开来了。

举例

val cc = '\''

每个字符都是 Char 类型的一个实例。更具体地讲,Char 就是 Unicode 字符。按照 Unicode 标准联盟的定义,Unicode 字符编码系统的设计 目的是实现“多种语言书面文字的互相转换、处理和显示”。

要声明一个字符,有两种方式。不过无论采用哪种方式,字符都要放在一对单引号里。

Kotlin 字符采用双字节 Unicode 编码,占两个字节(16位),因而可用十六进制(无符号的)编码形式表示,它们的表现形式是\uXXXX,其中XXXX为 16 位十六进制数,所以 'A' 字符也可以用 Unicode 编码 '\u0041' 表示。

val aChar: Char = 'a'

println(aChar)
println('\n') // Prints an extra newline character
println('\uFF00')

如果字符变量的值为数字,则可以使用 digtoInt ()函数显式地将其转换为 Int 数字。

布尔类型

Boolean 类型表示可以有两个值的 Boolean 对象: true 和 false。

Boolean 有一个可为空的对应项 Boolean? ,它也有空值。

布尔型的内置操作包括:

|| (逻辑或)

&& (逻辑与)

!(逻辑否)

其中 || and && 是惰性的。

常量和变量

Kotlin 有强大的类型推断能力。虽然你可以显式地声明变量的类型,但通常会让编译器通过推断来完成这项工作。Kotlin 并不强制执行不变性,尽管它是被推荐的。本质上使用 val/var。

在 Kotlin 中声明变量,就是在标识符的前面加上关键字 var。
变量一旦赋值就不能更改。要声明只读变量,使用 val 关键字。常量一旦初始化后就不能再被修改。

var a: String = "initial"  // 1
println(a)
val b: Int = 1             // 2
val c = 3                  // 3
  1. 声明一个变量 var 并初始化它。
  2. 声明一个不可变变量 val 并初始化它。
  3. 声明一个不可变变量,并在不指定类型的情况下初始化它。

你可以自由选择何时初始化变量,但是,它必须在第一次读之前初始化。

val d: Int  // 1

if (someCondition()) {
    d = 1   // 2
} else {
    d = 2   // 2
}

println(d) // 3
  1. 声明一个没有初始化的变量。
  2. 根据某些条件使用不同的值初始化变量。
  3. 读取变量是可能的,因为它已经被初始化了。

您可以在顶层声明变量。

val PI = 3.14
var x = 0

fun incrementX() {
    x += 1
}

编译时常量

编译时常量使用 const val 进行修饰。

编译时常量只能在函数(指包括 main 在内的所有函数)之外定义。这是因为编译时常量 必须在编译时(程序编译时)赋值,而 main 和其他函数都是在运行时(程序运行时)才调用, 函数内的变量也是在那时赋值。编译时常量要在这些变量赋值前就已存在。因为使用复杂的数据类型可能会危害编译时的安全保障,所以编译时常量只能是一些常见的基本数据类型。

  • String
  • Int
  • Double
  • Float
  • Long
  • Short
  • Byte
  • Char
  • Boolean
const val MAX_EXPERIENCE: Int = 5000

思考:使用 var 还是 val

如果两种方式都能满足需求情况下,原则上优先考虑使用 val 声明。因为一方面 val 声明的变量是只读,一旦初始化后不能修改,这可以避免程序运行过程中错误地修改变量内容;另一方面在声明引用类型使用 val,对象的引用不会被修改,但是引用内容可以修改,这样会更加安全,也符合函数式编程的技术要求。

Null Safety

为了消除 NullPointerException,Kotlin 的变量类型不允许赋值 null。如果您需要一个可以为空的变量,可以通过添加?在其类型的末端。

可空类型

有时候,Kotlin 程序需要使用 null 值,例如在与外部 Java 代码交互时,或者表示一个真正缺失的状态时。Kotlin 提供空跟踪来优雅地处理这种情况。

Kotlin 为每一种非空类型提供对应的可空类型(Nullable),就是在非空类型后面加上问号(?)表示可空类型。 var n: Int? = 10

Int? 是可空类型,它所声明的变量 n 可以接收空值。

var nullable: String? = "You can keep a null here"
nullable = null
  1. 接受可为空的字符串并返回其说明的函数。
  2. 如果给定的字符串不为空,也不为空,则返回有关其长度的信息。
  3. 否则,告诉调用方字符串为空或 null。

可空类型在具体使用时会有一些限制:

  • 不能直接调用可空类型对象的函数或属性。
  • 不能把可空类型数据赋值给非空类型变量。
  • 不能把可空类型数据传递给非空类型参数的函数。

类型转换

数值类型之间的转换

本节讨论数值类型之间互相转换,数值在进行赋值时采用的是显示转换,而在数学计算时采用的是隐式转换

赋值与显式转换

Kotlin 是一种安全的语言,对于类型的检查非常严格,不同类型数值进行赋值是禁止的. Kotlin中要想实现这种赋值转换,需要使用转换函数显式转换。Kotlin 的 6 种数值类型(Byte、Short、Int、Long、Float 和 Double),以及Char类型都有如下 7 个转换函数:

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double
  • toChar(): Char

数学计算与隐式转换

多个数值类型数据可以数学计算,由于参与进行数学计算的数值类型可能不同,编译器会根据上下文环境进行隐式转换。

参考

Kotlin 编程权威指南
https://www.ituring.com.cn/book/tupubarticle/27591?bookID=2610

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,859评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,772评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,956评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,729评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,611评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,441评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,850评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,485评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,770评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,803评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,598评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,434评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,856评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,065评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,365评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,852评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,065评论 2 338

推荐阅读更多精彩内容