Kotlin 2.1.0 入门教程(九)

devtools/2025/2/4 21:19:33/

类型检查和转换

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/devtools/156095.html

相关文章

计算机网络——流量控制

流量控制的基本方法是确保发送方不会以超过接收方处理能力的速度发送数据包。 通常的做法是接收方会向发送方提供某种反馈,如: (1)停止&等待 在任何时候只有一个数据包在传输,发送方发送一个数据包,…

caddy2配置http_basic用于验证用户名密码才允许访问页面

参考: basicauth (Caddyfile指令) — Caddy v2中文文档 1,查看caddy是否已经包含了Basic Auth插件 命令:caddy list-modules | grep http_basic 如果显示: http.authentication.providers.http_basic 则代表包含 Basic Auth 模…

linux下ollama更换模型路径

Linux下更换Ollama模型下载路径指南   在使用Ollama进行AI模型管理时,有时需要根据实际需求更改模型文件的存储路径。本文将详细介绍如何在Linux系统中更改Ollama模型的下载路径。 一、关闭Ollama服务   在更改模型路径之前,需要先停止Ollama服务。…

《程序人生》工作2年感悟

一些杂七杂八的感悟: 1.把事做好比什么都重要, 先树立量良好的形象,再横向发展。 2.职场就是人情世故,但也不要被人情世故绑架。 3.要常怀感恩的心,要记住帮助过你的人,愿意和你分享的人,有能力…

Java基础知识总结(二十六)--Arrays

用于操作数组对象的工具类&#xff0c;里面都是静态方法。 asList方法&#xff1a;将数组转换成list集合。 String[] arr {"abc","kk","qq"}; List<String> list Arrays.asList(arr);//将arr数组转成list集合。 将数组转换成集合&am…

OpenAI推出Deep Research带给我们怎样的启示

OpenAI 又发新产品了&#xff0c;这次是面向深度研究领域的智能体产品 ——「Deep Research」&#xff0c;貌似被逼无奈的节奏… 在技术方面&#xff0c;Deep Research搭载了优化后o3模型并通过端到端强化学习在多个领域的复杂浏览和推理任务上进行了训练。因没有更多的技术暴露…

最近最少使用算法(LRU最近最少使用)缓存替换算法

含义 最近最少使用算法&#xff08;LRU&#xff09;是一种缓存替换算法&#xff0c;用于在缓存空间有限的情况下&#xff0c;选择最少使用的数据项进行替换。该算法的核心思想是基于时间局部性原理&#xff0c;即刚被访问的数据在未来也很有可能被再次访问。 实现 LRU算法的…

Java 大视界 -- Java 大数据在生物信息学中的应用与挑战(67)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…