Kotlin 2.1.0 入门教程(九)

类型检查和转换

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

is!is 操作符

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

if (obj is String) {
    print(obj.length)
}

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

智能转换

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

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

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

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

if (x !is String) return

print(x.length) // x 自动转换为 String。

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

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

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

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

class Cat {
    fun purr() {
        println("Purr purr")
    }
}

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

fun main(){
    val kitty = Cat()
    petAnimal(kitty) // Purr purr
}

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

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

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

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

interface Status {
    fun signal() {}
}

interface Ok : Status
interface Postponed : Status
interface Declined : Status

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

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

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

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

interface Processor {
    fun process()
}

inline fun inlineAction(f: () -> Unit) = f()

fun nextProcessor(): Processor? = null

fun runProcessor(): Processor? {
    var processor: Processor? = null
    inlineAction {
        // 编译器知道 processor 是一个局部变量,且 inlineAction 是一个内联函数,
        // 因此对 processor 的引用不会泄漏,可以安全地对 processor 进行智能转换。

        // 如果 processor 不为 null,processor 会被智能转换。
        if (processor != null) {
            // 编译器知道 processor 不为 null,因此不需要安全调用。
            processor.process()
        }

        processor = nextProcessor()
    }

    return processor
}

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

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

val x: String = y as String

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

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

val x: String? = y as String?

安全(可空)转换操作符

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

val x: String? = y as? String

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962896.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

sobel边缘检测算法

人工智能例子汇总:AI常见的算法和例子-CSDN博客 Sobel边缘检测算法是一种用于图像处理中的边缘检测方法,它能够突出图像中灰度变化剧烈的地方,也就是边缘。该算法通过计算图像在水平方向和垂直方向上的梯度来检测边缘,梯度值越大…

MySQL为什么默认引擎是InnoDB ?

大家好,我是锋哥。今天分享关于【MySQL为什么默认引擎是InnoDB ?】面试题。希望对大家有帮助; MySQL为什么默认引擎是InnoDB ? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认引擎是 InnoDB,主要…

【Pytorch和Keras】使用transformer库进行图像分类

目录 一、环境准备二、基于Pytorch的预训练模型1、准备数据集2、加载预训练模型3、 使用pytorch进行模型构建 三、基于keras的预训练模型四、模型测试五、参考 现在大多数的模型都会上传到huggface平台进行统一的管理,transformer库能关联到huggface中对应的模型&am…

c语言进阶(简单的函数 数组 指针 预处理 文件 结构体)

c语言补充 格式 void函数头 {} 中的是函数体 sum函数名 &#xff08;&#xff09; 参数表 #include <stdio.h>void sum(int begin, int end) {int i;int sum 0;for (i begin ; i < end ; i) {sum i;}printf("%d到%d的和是%d\n", begin, end, sum); …

比较器使用

1 比较器是什么 2 使用比较器的注意事项 输出是否要接上拉电阻 2.1 推挽结构&#xff08;可以不用加上拉电阻&#xff09; 2.2 开漏结构&#xff08;OD,OC&#xff09;需要加上拉电阻 2.3 LM393 2.4 推挽和开漏 3 比较器的注意事项 输出是否要接上拉电阻 3.1 比较器内部有吸…

爬虫基础(三)Session和Cookie讲解

目录 一、前备知识点 &#xff08;1&#xff09;静态网页 &#xff08;2&#xff09;动态网页 &#xff08;3&#xff09;无状态HTTP 二、Session和Cookie 三、Session 四、Cookie &#xff08;1&#xff09;维持过程 &#xff08;2&#xff09;结构 正式开始说 Sessi…

项目升级Sass版本或升级Element Plus版本遇到的问题

项目升级Sass版本或升级Element Plus版本遇到的问题 如果项目有需求需要用到高版本的Element Plus组件&#xff0c;则需要升级相对应的sass版本&#xff0c;Element 文档中有提示&#xff0c;2.8.5及以后得版本&#xff0c;sass最低支持的版本为1.79.0&#xff0c;所升级sass、…

数据结构-Stack和栈

1.栈 1.1什么是栈 栈是一种特殊的线性表&#xff0c;只允许在固定的一段进行插入和删除操作&#xff0c;进行插入和删除操作的一段称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵顼后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#xff0c;就像一…

stm32硬件实现与w25qxx通信

使用的型号为stm32f103c8t6与w25q64。 STM32CubeMX配置与引脚衔接 根据stm32f103c8t6引脚手册&#xff0c;采用B12-B15四个引脚与W25Q64连接&#xff0c;实现SPI通信。 W25Q64SCK&#xff08;CLK&#xff09;PB13MOSI&#xff08;DI&#xff09;PB15MISO(DO)PB14CS&#xff08…

04树 + 堆 + 优先队列 + 图(D1_树(D8_B*树(B*)))

目录 一、基本介绍 二、相同思想和策略 三、不同的方式的磁盘空间利用 四、知识小结 一、基本介绍 B*树是Btree的变体&#xff0c;在B树的基础上(所有的叶子结点中包含了全部关键字的信息&#xff0c;及指向含有 这些关键字记录的指针)&#xff0c; B*树中非根和非叶子结…

Hot100之哈希

1两数之和 题目 思路解析 解法1--两次循环 解法2--哈希表一次循环 代码 解法1--两次循环 class Solution {public int[] twoSum(int[] nums, int target) {int nums1[] new int[2];int length nums.length;for (int i 0; i < length; i) {for (int j i 1; j < …

Autosar-以太网是怎么运行的?(原理部分)

写在前面&#xff1a; 入行一段时间了&#xff0c;基于个人理解整理一些东西&#xff0c;如有错误&#xff0c;欢迎各位大佬评论区指正&#xff01;&#xff01;&#xff01; 1.TCP/IP协议详解 TCP/IP协议包含了一系列的协议&#xff0c;也叫TCP/IP协议族&#xff08;TCP/IP P…

2025年大数据毕业设计选题推荐:数据分析与可视化 数据挖掘

目录 前言 毕设选题 开题指导建议 更多精选选题 选题帮助 最后 前言 大家好,这里是海浪学长毕设专题! 大四是整个大学期间最忙碌的时光&#xff0c;一边要忙着准备考研、考公、考教资或者实习为毕业后面临的升学就业做准备,一边要为毕业设计耗费大量精力。学长给大家整理…

如何在vs2022中处理python下无法输出中文问题

1.如何在vs2022中处理python下无法输出中文问题 进入vs界面时---工具菜单---自定义----在自定义窗口下选中”命令”页面----在菜单栏内----选择文件----再点击添加命令----左侧栏下滑找到文件-----在右侧往下拉找到并点击高级保存选项----再点击确定。 此时VS工程页面上会出现…

SSRF 漏洞利用 Redis 实战全解析:原理、攻击与防范

目录 前言 SSRF 漏洞深度剖析 Redis&#xff1a;强大的内存数据库 Redis 产生漏洞的原因 SSRF 漏洞利用 Redis 实战步骤 准备环境 下载安装 Redis 配置漏洞环境 启动 Redis 攻击机远程连接 Redis 利用 Redis 写 Webshell 防范措施 前言 在网络安全领域&#xff0…

UniApp开发的微信小程序主包过大问题及解决方案 编译小程序时Node-modules被打入主包

欢迎关注 『开发必备』 专栏,专注于解决你在开发过程中遇到的各种问题,帮你快速找到解决方案,节省大量调试时间。内容持续更新中,保证每篇都值得收藏! UniApp开发的微信小程序主包过大问题及解决方案 在使用UniApp开发微信小程序时,很多开发者都会遇到一个问题:打包后,…

Diffusion--人工智能领域的革命性技术

在人工智能领域&#xff0c;“diffusion”一词通常指的是“扩散模型”&#xff08;Diffusion Models&#xff09;&#xff0c;其全称为“Denoising Diffusion Probabilistic Models”&#xff08;DDPMs&#xff09;。扩散模型是一类生成式模型&#xff0c;它通过逐步去噪的方式…

升级到Mac15.1后pod install报错

升级Mac后&#xff0c;Flutter项目里的ios项目运行 pod install报错&#xff0c; 遇到这种问题&#xff0c;不要着急去百度&#xff0c;大概看一下报错信息&#xff0c;每个人遇到的问题都不一样。 别人的解决方法并不一定适合你&#xff1b; 下面是报错信息&#xff1a; #…

基于 oneM2M 标准的空气质量监测系统的互操作性

论文标题 英文标题&#xff1a; Interoperability of Air Quality Monitoring Systems through the oneM2M Standard 中文标题&#xff1a; 基于 oneM2M 标准的空气质量监测系统的互操作性 作者信息 Jonnar Danielle Diosana, Gabriel Angelo Limlingan, Danielle Bryan Sor…

利用Muduo库实现简单且健壮的Echo服务器

一、muduo网络库主要提供了两个类&#xff1a; TcpServer&#xff1a;用于编写服务器程序 TcpClient&#xff1a;用于编写客户端程序 二、三个重要的链接库&#xff1a; libmuduo_net、libmuduo_base、libpthread 三、muduo库底层就是epoll线程池&#xff0c;其好处是…