欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Kotlin 密封类的作用和方法

程序员文章站 2022-10-03 18:27:17
本文讲解 Kotlin 密封类的作用和用法。定义一个 Result 接口,用于表示某个操作的执行结果,然后定义两个类去实现 Result 接口:interface Result/** * 表示成功时的结果 */class Success(val msg: String) : Result/** * 表示失败时的结果 */class Failure(val error: Exception) : Result定义一个getResultMsg() 函数,用于获取最终执行结.....

本文讲解 Kotlin 密封类的作用和用法。

定义一个 Result 接口,用于表示某个操作的执行结果,然后定义两个类去实现 Result 接口:

interface Result

/**
 * 表示成功时的结果
 */
class Success(val msg: String) : Result

/**
 * 表示失败时的结果
 */
class Failure(val error: Exception) : Result

定义一个 getResultMsg() 函数,用于获取最终执行结果的信息:

fun getResultMsg(result: Result) = when (result) {
    is Success -> result.msg
    is Failure -> result.error.message
    else -> throw Exception()
}

getResultMsg() 函数中接收一个 Result 参数,通过 when 语句来判断,如果 Result 属于 Success,那么就返回成功信息;如果 Result 属于 Failure,那么就返回错误信息。

但是我们不得不在编写一个 else 条件,否则 Kotlin 编译器会认为这里缺少条件分支,代码将无法编译通过:

'when' expression must be exhaustive, add necessary 'else' branch

但实际上 Result 的执行结果只可能是 Success 或 Failure,这个 else 条件是永远走不到的,所以这里直接抛出了一个异常,只是为了满足 Kotlin 编译器的语法检查而已。另外,编写 else 条件还有一个潜在的风险。如果我们现在新增了一个 Unknown 类并实现 Result 接口,用于表示未知的执行结果,但是忘记在 getResultMsg() 函数中添加相应的条件分支,编译器在这种情况下是不会提醒我们的,而是会在运行的时候进入 else 条件里面,从而抛出异常导致程序崩溃。Kotlin 的密封类就很好地解决了这个问题。


密封类 sealed class

将 Result 接口改造成密封类的写法:

sealed class Result
 
/**
 * 表示成功时的结果
 */
class Success(val msg: String) : Result()
 
/**
 * 表示失败时的结果
 */
class Failure(val error: Exception) : Result()
将 interface 关键字改成 sealed class,由于密封类是一个可继承的类,因此在继承它的时候需要在后面加上一对括号。

改写成密封类之后,getResultMsg() 函数中的 else 条件已经不需要了:

fun getResultMsg(result: Result) = when (result) {
    is Success -> result.msg
    is Failure -> result.error.message
}
Q:为什么去掉了 else 条件仍然能编译通过?

A:因为在 when 语句传入一个密封类变量作为条件时,Kotlin 编译器会自动检查该密封类有哪些子类,并强制要求你将每一个子类所对应的条件全部处理。这样就可以保证即使没有编写 else 条件,也不可能出现漏写条件分支的情况。
密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。

希望本文对你有所帮助!


相关标签: Kotlin