Kotlin 2.1.0 入门教程(九)

server/2025/2/1 21:17:53/

类型检查和转换

Kotlin 中,可以执行类型检查以在运行时检查对象的类型。类型转换能够将对象转换为不同的类型。

is!is 操作符

要执行运行时检查以确定对象是否符合给定类型,请使用 is 操作符或其否定形式 !is

kotlin">if (obj is String) {print(obj.length)
}// 等同于 !(obj is String)。
if (obj !is String) { print("Not a String")
} else {print(obj.length)
}

智能转换

在大多数情况下,不需要使用显式转换操作符,因为编译器会自动转换对象。这称为智能转换。

编译器会跟踪不可变值的类型检查和显式转换,并在必要时自动插入隐式(安全)转换。

kotlin">fun demo(x: Any) {if (x is String) {print(x.length) // x 自动转换为 String。}
}

编译器甚至足够聪明,知道如果否定检查导致返回,则转换是安全的。

kotlin">if (x !is String) returnprint(x.length) // x 自动转换为 String。

智能转换不仅适用于 if 条件表达式,还适用于 when 表达式和 while 循环。

kotlin">when (x) {is Int -> print(x + 1)is String -> print(x.length + 1)is IntArray -> print(x.sum())
}

如果在 ifwhenwhile 条件中使用布尔类型的变量之前声明它,那么编译器收集的有关该变量的任何信息都可以在相应的块中用于智能转换。

当您希望将布尔条件提取到变量中时,这非常有用。然后,您可以为变量赋予一个有意义的名称,这将提高代码的可读性,并使得稍后在代码中重用该变量成为可能。例如:

kotlin">class Cat {fun purr() {println("Purr purr")}
}fun petAnimal(animal: Any) {val isCat = animal is Catif (isCat) {// 编译器可以访问有关 isCat 的信息,因此它知道 animal 已被智能转换为 Cat 类型。// 因此,可以调用 purr 函数。animal.purr()}
}fun main(){val kitty = Cat()petAnimal(kitty) // Purr purr
}

如果在逻辑与 && 或逻辑或 || 运算符的左侧有一个类型检查(正向或负向),编译器可以在右侧执行智能类型转换。

kotlin">// 在 || 的右侧,x 自动被转换为 String 类型。
if (x !is String || x.length == 0) return// 在 && 的右侧,x 自动被转换为 String 类型。
if (x is String && x.length > 0) {print(x.length)
}

如果你将对象的类型检查与逻辑或 || 运算符结合使用,智能类型转换会将它们转换为它们的最近公共超类型。

kotlin">interface Status {fun signal() {}
}interface Ok : Status
interface Postponed : Status
interface Declined : Statusfun signalCheck(signalStatus: Any) {if (signalStatus is Postponed || signalStatus is Declined) {// signalStatus 被智能转换为公共超类型 Status。signalStatus.signal()}
}

编译器可以对传递给内联函数的 Lambda 函数中捕获的变量进行智能转换。

内联函数被视为具有隐式的 callsInPlace 契约。这意味着传递给内联函数的任何 Lambda 函数都是在原地调用的。由于 Lambda 函数是原地调用的,编译器知道 Lambda 函数不会泄漏对其函数体内包含的任何变量的引用。

编译器利用这些知识以及其他分析来决定是否可以对捕获的变量进行智能转换。

kotlin">interface Processor {fun process()
}inline fun inlineAction(f: () -> Unit) = f()fun nextProcessor(): Processor? = nullfun runProcessor(): Processor? {var processor: Processor? = nullinlineAction {// 编译器知道 processor 是一个局部变量,且 inlineAction 是一个内联函数,// 因此对 processor 的引用不会泄漏,可以安全地对 processor 进行智能转换。// 如果 processor 不为 null,processor 会被智能转换。if (processor != null) {// 编译器知道 processor 不为 null,因此不需要安全调用。processor.process()}processor = nextProcessor()}return processor
}

智能转换信息会传递给 catchfinally 块。这使得您的代码更安全,因为编译器会跟踪您的对象是否具有可空类型。

kotlin">fun testString() {var stringInput: String? = null// stringInput 被智能转换为 String 类型。stringInput = ""try {// 编译器知道 stringInput 不为 null。println(stringInput.length) // 0// 编译器拒绝之前的智能转换信息,// 现在 stringInput 恢复为 String? 类型。stringInput = null// 触发异常。if (2 > 1) throw Exception()stringInput = ""}catch (exception: Exception) {// 编译器知道 stringInput 可能为 null,因此 stringInput 保持可空类型。println(stringInput?.length) // null}
}

智能转换的前提条件

请注意,智能类型转换仅在编译器能够保证变量在检查和使用之间不会发生变化时才有效。

智能类型转换可以在以下条件下使用:

  • val 局部变量:

    • 始终有效,除了局部委托属性。
  • val 属性:

    • 如果属性是 privateinternal,或者检查是在声明属性的同一模块中执行的。

    • 智能转换不能用于 open 属性或具有自定义 getter 的属性。

  • var 局部变量:

    • 如果变量在检查和使用之间未被修改,未被捕获在修改它的 Lambda 中,并且不是局部委托属性。
  • var 属性:

    • 永远不能使用,因为变量可能随时被其他代码修改。

不安全的转换操作符

要将对象显式转换为非空类型,请使用不安全的转换操作符 as

kotlin">val x: String = y as String

如果转换不可能,编译器会抛出异常。这就是为什么它被称为不安全的原因。

在前面的示例中,如果 ynull,上面的代码会抛出异常。这是因为 null 不能转换为 String,因为 String 不是可空类型。为了使示例适用于可能的空值,请在转换的右侧使用可空类型:

kotlin">val x: String? = y as String?

安全(可空)转换操作符

为了避免异常,请使用安全转换操作符 as?,它在失败时返回 null

kotlin">val x: String? = y as? String

请注意,尽管 as? 的右侧是非空类型 String,但转换的结果是可空的。

as? 是一种安全的类型转换方式,即使转换失败也不会抛出异常,而是返回 null


http://www.ppmy.cn/server/164168.html

相关文章

MySQL查询优化(三):深度解读 MySQL客户端和服务端协议

如果需要从 MySQL 服务端获得很高的性能,最佳的方式就是花时间研究 MySQL 优化和执行查询的机制。一旦理解了这些,大部分的查询优化是有据可循的,从而使得整个查询优化的过程更有逻辑性。下图展示了 MySQL 执行查询的过程: 客户端…

提示词工程

1、什么构成了一个好的提示 提示:输入给AI的问题或指令 好的提示能极大地提高AI的理解和执行的效率,让AI提供更准确和有用的回答。 提示工程(Prompt Engineering):研究如何写出好的提示 提示工程原则: …

阿里云域名备案

一、下载阿里云App 手机应用商店搜索"阿里云",点击安装。 二、登录阿里云账号 三、打开"ICP备案" 点击"运维"页面的"ICP备案"。 四、点击"新增网站/App" 若无备案信息,则先新增备案信息。 五、开始备案

OPENPPP2 —— VMUX_NET 多路复用原理剖析

在阅读本文之前,必先了解以下几个概念: 1、MUX(Multiplexer):合并多个信号到单一通道。 2、DEMUX(Demultiplexer):从单一通道分离出多个信号。 3、单一通道,可汇聚多个…

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)

手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍) 目录 手撕Diffusion系列 - 第九期 - 改进为Stable Diffusion(原理介绍)DDPM 原理图Stable Diffusion 原理Stable Diffusion的原理解释Stable Diffusion 和 Diffus…

Deep Seek R1本地化部署

目录 说明 一、下载ollama 二、在ollama官网下载模型 三、使用 后记 说明 操作系统:win10 使用工具:ollama 一、下载ollama 从官网下载ollama: ollama默认安装在C盘,具体位置为C:\Users\用户名\AppData\Local\Programs\O…

leetcode刷题记录(九十)——74. 搜索二维矩阵

(一)问题描述 74. 搜索二维矩阵 - 力扣(LeetCode)74. 搜索二维矩阵 - 给你一个满足下述两条属性的 m x n 整数矩阵: * 每行中的整数从左到右按非严格递增顺序排列。 * 每行的第一个整数大于前一行的最后一个整数。给你…

自制虚拟机(C/C++)(一、分析语法和easyx运用,完整虚拟机实现)

网上对虚拟机的解释很多,其实本质就一句话 虚拟机就是机器语言解释器 我们今天要实现汇编语言解释器,下一次再加上ndisasm反汇编器就是真正虚拟机了 注:这里的虚拟机指的是VMware一类的,而不是JVM,python一样的高级语言解释器 …